> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting: FILE_SCAN_QUARANTINED

> Recover from the 402 FILE_SCAN_QUARANTINED response on file downloads and attachments — read the scan state machine, poll until clean, and escalate a wrong verdict.

# Troubleshooting: FILE\_SCAN\_QUARANTINED

A download attempts fails with a `402` and `error.code` equal to
`FILE_SCAN_QUARANTINED`:

```json theme={null}
{
  "error": {
    "code": "FILE_SCAN_QUARANTINED",
    "message": "This upload is temporarily quarantined by the content scanner.",
    "status": 402,
    "details": { "scan_id": "scan_0192", "scan_eta_seconds": 7 }
  }
}
```

This is not a billing gate and not a permission failure — the file is held
inside the content-scanner's review state machine. The envelope carries a
`scan_id` and a `scan_eta_seconds` estimate precisely so you can poll to a
verdict instead of guessing.

## What the scan state machine does

Every uploaded file moves through three states:

* **`pending`** — the upload landed and the scanner has not reached a verdict
  yet. A download or attachment fetch on a `pending` file returns
  `FILE_SCAN_QUARANTINED` while the scan completes.
* **`clean`** — the scanner returned no threat. Downloads succeed from here
  on.
* **`quarantined`** — the scanner flagged the content. The file is dropped
  before it can reach a delivery, an attachment fetch, or an AI agent, exactly
  like an inbound-email attachment the threat scan flags malicious: the
  quarantine is a fault-line decision, not a suppression rule.

The hold is deliberate. Where a file is consumed by downstream surfaces —
email attachments, MMS payloads, knowledge-base ingestion, agent context —
serving the bytes before the verdict would pass suspect content to your
recipient. The 402 stops that pass until the scanner answers.

## Check scan\_status before deciding

Look up the file row with
`GET /api/v1/files/{id}`
and read the row's scan fields. A `pending` row is a wait case; a
`quarantined` row is a replace case. The `details.scan_id` in the 402 envelope
identifies the individual scan run — keep it when you escalate a verdict, so
support can read the same scanner verdict you got rather than re-guessing
from the file bytes.

## Retry semantics: poll to clean, never replay the artifact

Poll-safe and replay-unsafe live in one loop, so branch on the state:

| State on poll         | Response          | Move                                                                                                                  |
| --------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------- |
| `pending` (402 again) | transient hold    | Poll again after `details.scan_eta_seconds` with a bounded retry loop                                                 |
| `clean`               | verdict reached   | Re-issue the download — it now succeeds                                                                               |
| `quarantined`         | permanent verdict | Stop polling. Replace the artifact and re-upload a cleaned file — replaying the same quarantined bytes never heals it |

The contrast with a DLQ retry matters: a dead-letter entry is a delivery
artifact you *replay* after fixing its fault. A quarantined file is never
replayed — the scanner verdict attaches to the content itself. If you
blind-retry a quarantined artifact on every poll tick you also burn the
rate-limit budget on deterministic 402s; bound the loop to the ETA the
envelope gives you.

## Tenant-owned first controls

A true-positive verdict starts at your own intake rules, which you control
per tenant:

* **Allowed content types** — uploads outside your allow-list fail
  pre-flight before they ever enter the scanner. Tighten the list to the
  types your flows genuinely accept.
* **Size ceilings** — a file above your upload cap is rejected at intake;
  the scanner never sees it.
* **Uploader allowlists and endpoint hygiene** — quarantines cluster on the
  uploaders and endpoints that accept arbitrary binaries from the outside.
  Restrict who can push content and the verdict rate falls with it.

Check these before treating a verdict as wrong: if your intake routinely
admits executable-shaped payloads or renamed content, a `quarantined` verdict
is the scanner doing its job, and the fix belongs in the intake rule, not in
an escalation.

## Escalate a wrong verdict

When a benign, business-critical file is held — and the intake rules above
check out — open a support ticket with three things: the file ID, the
`scan_id` from the 402 envelope, and a short note on why the content type is
expected in your flow. Support reads the same scanner verdict and either
confirms the hold or restores the file on the platform side. Re-uploading the
identical bytes without this step re-enters the same verdict, so escalate
first when the content matters.

## See also

* [Files API](/api-reference/endpoints/files) — the list/get endpoints that
  carry the scan fields, plus upload and download.
* [Troubleshooting: fan-out and upload errors](/troubleshooting/fan-out-and-upload-errors)
  — the sibling intake-rejection codes (`INVALID_FILE_TYPE`,
  `MAGIC_BYTE_MISMATCH`, `FILE_TOO_LARGE`) that fail before the scanner runs.
* [Glossary: Quarantine](/reference/glossary) — how a fault-driven hold
  differs from a permanent DLQ exhaust lane.
