domain_not_ready
HTTP 422 retryable: false REST and MCP
The domain exists but at least one of its readiness states is not satisfied, so an inbox cannot be created on it yet.
Why it happens
A domain is not ready as a single boolean. Four states must all be right before an inbox can hang off it: ownership_status verified, provider_attach_state attached, sending_status ready and receiving_status ready. All four are checked together, and then checked again after the provider inbox has been created, along with the provider domain id and the ownership generation. That second check catches a domain whose readiness changed while provisioning was in flight, and in that case the inbox is left paused for support review rather than being activated or silently deleted.
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.
- Creating an inbox on a domain whose ownership, provider attachment, sending or receiving state is not yet ready.
packages/domain/src/custom-domains.ts:765 - Readiness, the provider domain id, or the ownership generation changed between the start of provisioning and the commit. The inbox stays paused.
packages/domain/src/custom-domains.ts:858 - The platform receiving domain itself has no ready, active, unretired record with a provider domain id and provider account id.
packages/domain/src/platform-inboxes.ts:71
How to fix it
- Read the domain with GET /projects/{project_id}/domains/{domain_id} and look at which of the four states is not ready. The error does not name it; the resource does.
- Publish the DNS records and then call the verify endpoint. Verification is not automatic on a schedule you control.
- Allow for DNS propagation before re-verifying. Records published seconds ago will not be visible to the resolver yet.
- If an inbox is paused after a mid-provisioning change, contact support with the request id rather than retrying. Retrying cannot resolve an ambiguous provisioning outcome.
Why it works this way
The ownership generation is re-checked at commit specifically so that a domain removed and re-added during provisioning does not inherit the in-flight inbox. Without it, an inbox could attach to a domain that is nominally the same name but a different ownership record.
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.
POST /projects/{project_id}/domains/{domain_id}/verifyGET /projects/{project_id}/domains/{domain_id}POST /projects/{project_id}/inboxes
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": "domain_not_ready",
"message": "Ownership, sending, and receiving must all be verified before creating an inbox.",
"request_id": "req_...",
"retryable": false
}
}
Verified against packages/domain/src/custom-domains.ts:765. The status comes from ERROR_STATUS in packages/contracts/src/errors.ts, which is the one
place a code is mapped to a status.