Skip to main content

Troubleshooting: ATTACHMENT_STORAGE_UNAVAILABLE

Uploading a file in the Inbox attachment panel on a ticket fails with a 503 and error.code equal to ATTACHMENT_STORAGE_UNAVAILABLE:
You see this on the proxy-upload call POST /api/v1/inbox/tickets/:id/attachments/:attId/content — the upload reached the API, passed validation, and then the object storage write failed. The same code can surface on the registered-attachment flow when the signed upload path hits the same backend fault, and on attachment downloads that read from the same private bucket.

Cause split: a storage fault, not a validation problem

ATTACHMENT_STORAGE_UNAVAILABLE is the classifier for “the storage backend timed out or blew a 5xx.” It fires after every intake gate has passed, so the file itself is never the problem:
  • File too large → 413 ATTACHMENT_TOO_LARGE
  • Empty body or malformed multipart → 422 / 415
  • Ticket or attachment id wrong, or outside your organization → 404 / 422
Only when all of those clear and the write to the private attachment bucket still fails does the route demote the fault to this 503. Re-encoding the file, changing its format, or trimming its name will never fix a 503 from this code — the bytes never reached the decision point that rejects content. The underlying truth is two-part: either the storage backend had a transient incident (timeout, rolling restart, brief 5xx), or the deployment’s bucket / permission wiring drifted and the write fails the same way every time. The retry path handles the first; the escalation path is for the second.

Owner actions: retry with backoff, then escalate with evidence

The upload is idempotent from your side — the attachment row was not committed, so re-uploading the same file cannot create duplicates or half-rows.
  1. Re-upload the same file after a short wait. A single retry inside the dashboard covers most transient incidents.
  2. If the failure repeats, use exponential backoff (roughly 1s, 2s, 4s, 8s, capped at ~1 minute) instead of hammering the endpoint — a tight loop burns your rate-limit budget against a backend that is already failing.
  3. If the failure repeats with the same file at backoff, treat it as a persistent storage fault and contact support with two things:
    • the meta.request_id returned on the failed response — it pins the exact upload attempt in the platform log, and
    • the checksum of the file bytes (compute sha256 of the file and send the hex). Support matches the checksum against the ingestion logs rather than re-deriving the file contents from your description.
Keep the failed attempt’s response in the ticket so the request_id and checksum pair travels together; either alone forces support to guess.

Tenant-owned first controls

Nothing about this fault is tenant-owned — it maps to platform storage infrastructure, not your configuration. The only tenant-side control is the upload hygiene that keeps you out of the validation codes above: stay inside your organization’s attachment size ceiling so a genuine oversize file lands on 413 (a fixable client fault), not a 503 (a platform fault). If you see ATTACHMENT_STORAGE_UNAVAILABLE, your configuration is exonerated by definition and the fix is on the platform side.

What NOT to do

  • Do not strip the message from the Inbox thread. The failure is scoped to storage only — the conversation, the ticket, and the message text are intact. Delete-and-recreate removes context and gains nothing; the upload channel is the only thing at fault.
  • Do not edit the file and re-upload a renamed variant. A storage 503 does not read the format; a changed name makes support triage harder by breaking the checksum you eventually send.
  • Do not delete-and-recreate the attachment row via the API. There is no committed row for the failed attempt — the crash happens before commit — so a cleanup call has no target.
  • Do not disable attachment uploads at the tenant level. A storage-unavailable fault is not a permission or policy gate; toggling a feature flag just hides a retryable error behind a different one.

Escalate

If backoff-clean retries keep returning ATTACHMENT_STORAGE_UNAVAILABLE for the same file, open a support ticket with the meta.request_id from the last response plus the sha256 of the bytes. Support reads the platform storage log for that exact attempt, confirms whether the backend is mid-incident, and either confirms the retry window or restores the write path. Do not keep uploading new instances of the same attachment while you wait — you only multiply failed rows’ signal without changing the outcome.

See also

  • Files API — the sibling upload/download endpoints, and the scan-state fields that gate downloads of quarantined content.
  • Troubleshooting: FILE_SCAN_QUARANTINED — the intake-adjacent 402 family where the same upload surface instead holds a file inside the content-scanner’s verdict path. The split is scan-state-first vs storage-first: a 402 is the scanner saying hold, a 503 is the backend saying I can’t accept.
  • Error Code Reference — the envelope shape that carries the request_id you escalate with.