3.2

Part

Every piece of content in A2A is a Part that holds exactly one of text, raw, url, or data, and its mediaType says how to read it.

Your planner asks code-reviewer to review a diff. The request carries an instruction and the diff as a file, and the answer carries findings that the planner's own code will parse. A2A carries all three in one container shape, the part, and labels each one with a media type.

When you finish this section, you can build all four kinds of part and predict whether an agent will accept them.

One container, four contents

Part: the smallest unit of content in a message or an artifact. In the proto, Part declares its content as a oneof with four members:

  • text holds a string.
  • raw holds the bytes of a file. In JSON, the bytes are a base64 string.
  • url holds a URL that points to the content of the file.
  • data holds any structured value as JSON: an object, an array, a string, a number, a boolean, or null.

Beside the content sit three optional fields, mediaType, filename, and metadata, and mediaType works for every kind of part. The kit's review request sends two kinds in one message:

one message, two kinds of partjsonFull log
      "parts": [
        {
          "text": "Review this diff of payments-api."
        },
        {
          "raw": "LS0tIGEvcGF5bWVudHMvcmVmdW5kcy5weQor…",
          "filename": "refunds.diff",
          "mediaType": "text/x-diff"
        }
      ]
The parts array of the planner's first message to code-reviewer. The base64 value of raw is cut after 36 of its 236 characters.

Base64 costs size: the 175-byte diff of payments/refunds.py becomes 236 characters in the JSON body. A url part keeps the message small and leaves the download, with its risk, to the receiver.

No kind, no nesting

In version 0.3, a part named its type in a kind field and wrapped a file in a nested file object. Version 1.0 removed both. The kind field is no longer part of the protocol, and a sender should not write it.

A file part is flat: raw or url sits next to filename and mediaType. The specification's own file-part sample has that shape but is not valid JSON (conflict D24). Copy part shapes from the proto, never from the samples.

Read a part by testing which content member is present, and never send two of them. The reference SDK refuses a part with two members as invalid parameters, -32602, before any agent code runs. It ignores a stray kind, as the specification asks: an implementation should ignore fields that it does not recognize.

Fig. 3.2four kinds of part from the kitstructure
Four kinds of part Top: a part holds exactly one of four content members, text, raw, url or data, and every kind can also carry mediaType, filename and metadata. Below, four parts from the captures in the order they were sent: the refunds.diff file the planner sent as raw base64 with media type text/x-diff, the code-reviewer question as text, the review findings as a data part with media type application/json, and a url part labelled image/png that code-reviewer rejects with error -32005 CONTENT_TYPE_NOT_SUPPORTED. ONE PART HOLDS EXACTLY ONE OF OPTIONAL ON EVERY KIND text raw url data mediaType filename metadata FOUR PARTS FROM THE CAPTURES, IN THE ORDER THEY WERE SENT raw LS0tIGEvcGF5bWVudHMvcmVmdW5kcy5weQor first 36 of 236 base64 characters filename "refunds.diff" mediaType "text/x-diff" sent by the planner, a five-line diff · 06-input-required.http text "Which base branch should I compare this diff against?" mediaType absent: the kit reads it as text/plain sent by code-reviewer in status.message · 06-input-required.http data "base": "main" plus "findings", two objects with file, line, severity, finding mediaType "application/json" part 2 of the review.json artifact, sent by code-reviewer · 06-input-required.http url "https://example.com/screenshot.png" mediaType "image/png" sent by the planner · 11-errors.http CONTENT_TYPE_NOT_SUPPORTED rejected with error -32005
The kit's captures use all four kinds of part, and only the image/png part fails, because code-reviewer does not accept that media type. The top row is the shape of every part. Each row below is one captured part, in the order the captures sent them. Its content member is on the left, its media type in green, and its sender underneath. The review.json artifact holds a text part for a person and a data part for code.

Who declares media types

Media types are declared in four places, and a skill's modes override the card's defaults:

FieldLives inSet bycode-reviewer in the kit
defaultInputModesthe agent cardthe agenttext/plain, text/x-diff
defaultOutputModesthe agent cardthe agenttext/plain, application/json
inputModes, outputModeseach skill on the cardthe agentreview-diff takes text/x-diff and text/plain
acceptedOutputModesconfiguration of a sendthe clientnot sent anywhere in the kit
mediaTypeeach partwhoever sends the parttext/x-diff on refunds.diff

The client's one field is acceptedOutputModes, and the rule on the agent is a SHOULD. The agent should use the field to shape its output. The SDK's request handler never reads the field, so check the mediaType of every part you receive.

When the media type does not fit

ContentTypeNotSupportedError: the agent or the called skill does not support a media type that the message parts give or that an artifact implies. Its JSON-RPC code is -32005, and errors gives its other forms.

In the kit, the planner sends code-reviewer a screenshot as a url part labelled image/png, and the agent refuses before it creates a task:

a media type the agent does not acceptjsonFull log
      "parts": [
        {
          "url": "https://example.com/screenshot.png",
          "mediaType": "image/png"
        }
      ]
…
  "error": {
    "code": -32005,
    "message": "Content type not supported",
    "data": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "CONTENT_TYPE_NOT_SUPPORTED",
        "domain": "a2a-protocol.org",
        "metadata": {
          "mediaType": "image/png"
        }
Exchange 5, cut to the part that was sent and the error that came back inside an HTTP 200 response.

Servers check differently, because the specification gives an unlabelled part no default type. The SDK checks only when the server turns the check on, and then it skips every part with no mediaType. The kit gives such a part a default type and checks it against the card's defaultInputModes, as the kit README lists. The same unlabelled part can pass one server and fail the other.

The security rules ask agents to reject media types that they do not expect. A url part must be checked against server-side request forgery, as security requirements explains.

A2A protocol 1.0.1 · 3303592 · 2026-05-28 · Edition 2026.10