Error reference

attachment_not_ready

HTTP 422 retryable: false REST and MCP

The attachment exists but its scan has not completed cleanly, so it cannot be sent or downloaded.

Why it happens

A file is usable only when every one of several states lines up: the attachment row is ready, its scan_status is clean, the underlying object is ready, and the recorded SHA-256 matches the object registry's digest. That last comparison is the interesting one. It means a file whose stored bytes no longer hash to what was scanned is treated as not ready, so a clean scan result cannot be inherited by different content. On the download side the same code covers a file that was purged or rejected.

Every condition below was read in the implementation at the file and line given. They are the branches that raise this code, not a summary of what the name suggests.

How to fix it

  1. Poll the upload with GET /projects/{project_id}/uploads/{upload_id} until it reports a clean scan, then send. Scanning is asynchronous and completing the upload does not complete the scan.
  2. Complete the upload before attaching it. Reserve, PUT the content, then call complete; an attachment that skipped completion never reaches a scannable state.
  3. If the scan rejected the file, do not retry with the same bytes. A rejected file stays rejected.
  4. Check that you are attaching the upload id, not the object id or the message id.

Why it works this way

Comparing the recorded hash against the object registry digest at send time, rather than trusting the scan flag alone, is what stops a clean verdict from being transferable to content that was swapped underneath it.

Messages you will see

The message field is written for a human reading a log and is not a contract value. Branch on code instead. These are the exact strings this code is sent with today, listed so that a search for one of them lands here.

Where it appears

These are the documented surfaces that raise it. The REST base is https://api.emailforagents.ai/v1, and the remote MCP endpoint is https://mcp.emailforagents.ai/mcp.

The response

Read request_id off the body or the x-request-id header before doing anything else. It is the only handle on one specific attempt, and for a 503 it is the only handle at all, because the underlying detail stays server-side.

HTTP/1.1 422
content-type: application/json
x-request-id: req_...

{
  "error": {
    "code": "attachment_not_ready",
    "message": "This file cannot be downloaded until a successful scan marks it clean.",
    "request_id": "req_...",
    "retryable": false
  }
}

Verified against packages/domain/src/services.ts:3851. The status comes from ERROR_STATUS in packages/contracts/src/errors.ts, which is the one place a code is mapped to a status.

All error codes · Documentation · Quickstart