Troubleshooting: ATTACHMENT_TOO_LARGE and AUDIO_TOO_LARGE
These two codes are deterministic size caps: the API rejected the payload before any upload happened, so nothing was stored and nothing will change on retry.ATTACHMENT_TOO_LARGE fires on Inbox ticket
attachments past the 25 MiB per-attachment ceiling. AUDIO_TOO_LARGE
fires on an audio clip past the surface’s limit — most commonly a
voice-upload endpoint that accepts up to 2 MB, or the voice-biometrics
enrollment sample capped at 30 seconds / 2 MB. Both are fixable on the
sender side: reduce the bytes and retry once. A third code on the same
ticket-upload surface counts attachments instead of bytes:
ATTACHMENT_LIMIT_REACHED (409) refuses a ticket that already holds its
maximum, no matter how small the file is — section 2 separates it from
the size caps.
1. Which cap is which
Match the surface you were calling to the cap it enforces:
The limit differs per surface because the downstream consumer differs:
a ticket attachment lands in object storage, while an audio clip goes
straight to a media or biometrics pipeline that decodes it in memory.
Always read the size limit for the exact endpoint in its
API reference entry — the cap in the error message is
the byte ceiling for the surface you hit, stated in bytes.
If you instead received
ATTACHMENT_STORAGE_UNAVAILABLE (503) on a
ticket upload, that is not a size cap — the file passed every
intake check and the storage write failed. Route to the
attachment storage unavailable runbook
instead of this page.
2. Size caps vs the per-ticket count cap
A third refusal on the ticket-upload surface measures neither bytes nor content type:ATTACHMENT_LIMIT_REACHED (409) fires when the ticket
already holds the maximum number of attachments, so a file that is small
and a permitted type is still refused. The size caps above count bytes
per file; this one counts attachments per ticket, and the fix is freeing
headroom, not shrinking the file.
The 409 message embeds the maximum it compared against:
Read the current count
GET /api/v1/inbox/tickets/:id/attachments returns the ticket’s
attachment index as items, oldest first. The number of items is the
count the cap compares against, and every stored attachment counts:
files linked to a reply and files attached to the ticket itself, from
every teammate who uploaded. The cap sits at 50 and the list returns up
to 200 rows, so what you see is the full count; the dashboard’s ticket
attachment panel shows the same list.
Free a slot, then upload
- Delete, then upload.
DELETE /api/v1/inbox/tickets/:id/attachments/:attIdremoves a superseded or duplicate file and frees its slot immediately; the next register call succeeds. - Replace in place. If the new file supersedes one already on the
ticket, upload the new bytes to the existing attachment with
POST /api/v1/inbox/tickets/:id/attachments/:attId/contentinstead of registering a fresh row — the count never moves.
3. Diagnose the rejection
Work the response before touching the file:- Read the
code.ATTACHMENT_TOO_LARGEmeans a byte ceiling;UNSUPPORTED_MEDIA_TYPE(422/415) means a content-type or multipart problem — shrinking the file will not clear a type rejection. - Read the
message. It states the exact ceiling in bytes that tripped. Compare it against the file size you sent. - Check where the cap fired. On the ticket-attachment register
call the check runs against the declared
size_bytesin your JSON body; on the multipart upload call it runs against the actual bytes received. A mismatch between the two (declared under, actual over) fails at the upload step. - Confirm the retry shape. Retry with the same bytes and you get the same code, every time — the check is deterministic. Only a smaller payload changes the outcome.
4. Fix: bring the payload under the cap
- Ticket attachments (25 MiB). Compress the file first: a PDF re-exported with compression, an image resized to its display resolution, or a screen recording re-exported at a lower bitrate usually drops well under the ceiling. For genuinely larger evidence (long recordings, full log dumps), split the file into parts and attach them as separate uploads, or put the file in your own cloud storage and paste a link into the ticket reply — the message thread carries the reference and the cap never engages.
- Audio uploads (2 MB class). Re-encode, not just rename. A stereo
44.1 kHz WAV at 1411 kbps becomes mono 16 kHz MP3 in the tens of
kbps — indistinguishable for prompts and IVR audio. Any encoder
(e.g.
ffmpeg -i in.wav -ac 1 -b:a 64k out.mp3) gets a minute of speech comfortably under 2 MB. - Voice-biometrics samples (30 s / 2 MB). Trim the clip. The enrollment verifier needs a few seconds of clean speech; long silences, intros, or repeated phrases only burn the cap. On this surface the cap is both a duration and a byte check, so shorten the recording rather than compressing it.
size_bytes after the upload succeeds.
5. What not to do
- Do not retry the identical payload. The cap check runs before any storage write, so a repeat call re-rejects identically and only burns rate-limit budget.
- Do not rename or container-swap the file. Wrapping the same
bytes in a
.zipor changing the extension does not reduce the measured size, and on the register call a renamed mismatch betweencontent_typeand the actual bytes can move you intoUNSUPPORTED_MEDIA_TYPE. - Do not treat
ATTACHMENT_STORAGE_UNAVAILABLE(503) as this page’s problem. A 503 means validation passed and storage failed; a 422/413 here means validation failed. The remediation directions are opposite — retry the same file for the former, shrink it for the latter. - Do not shrink a file that failed with
ATTACHMENT_LIMIT_REACHED(409). The 409 measures count, not bytes — a smaller file repeats the same refusal until a slot is free or the upload replaces an existing attachment in place.
6. Escalation payload
You should be able to clear this class on your side — the cap is tenant-owned input hygiene, not a platform fault. Escalate only if the response you see contradicts the file you sent (e.g. a 4 MB file rejected as over-limit), and include:- Your tenant id (dashboard → Settings → Organization, or
organizationIdfromGET /api/v1/me). - The endpoint you called and the object id — the ticket id, or the voice-biometrics session/sample id.
- The file size in bytes you sent (and the declared
size_byteson the register call, if different). - The full error envelope, including
meta.request_idfrom the failed response.
See also
- Troubleshooting: ATTACHMENT_STORAGE_UNAVAILABLE — the 503 storage-fault sibling on the same ticket-upload surface.
- Troubleshooting: fan-out and upload rejections
— the wider upload-validation cluster (
INVALID_FILE_TYPE,INVALID_AUDIO,MAGIC_BYTE_MISMATCH) that sits beside these two size codes. - Troubleshooting: MEDIA_UPLOAD_FAILED — the 502-class upload/download failures where the platform, not your payload, is the problem.
- Error codes reference — the envelope and per-code table entries for both codes.
- Troubleshooting hub — find this page in the hub’s Inbox assignment and lifecycle accordion.
- FAQ — “My ticket attachment upload returned 503 ATTACHMENT_STORAGE_UNAVAILABLE” — the QA angle that triages a size-cap rejection from a storage fault.