Skip to main content

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/:attId removes 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/content instead of registering a fresh row — the count never moves.
Nothing retries automatically. Like the size caps, the 409 is deterministic: the same register call repeats identically until the count drops below the maximum.

3. Diagnose the rejection

Work the response before touching the file:
  1. Read the code. ATTACHMENT_TOO_LARGE means a byte ceiling; UNSUPPORTED_MEDIA_TYPE (422/415) means a content-type or multipart problem — shrinking the file will not clear a type rejection.
  2. Read the message. It states the exact ceiling in bytes that tripped. Compare it against the file size you sent.
  3. Check where the cap fired. On the ticket-attachment register call the check runs against the declared size_bytes in 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.
  4. 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.
After shrinking, retry the same call once. The register + upload sequence for ticket attachments is two calls; resend the register call with the corrected 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 .zip or changing the extension does not reduce the measured size, and on the register call a renamed mismatch between content_type and the actual bytes can move you into UNSUPPORTED_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:
  1. Your tenant id (dashboard → Settings → Organization, or organizationId from GET /api/v1/me).
  2. The endpoint you called and the object id — the ticket id, or the voice-biometrics session/sample id.
  3. The file size in bytes you sent (and the declared size_bytes on the register call, if different).
  4. The full error envelope, including meta.request_id from the failed response.
That set lets support replay the exact validation decision instead of re-measuring your file from a description.

See also