skip to content

Error codes

Broker, MCP, OAuth, provider and inbox errors with status, retryability and the next action, including the v1.2 RP trust codes.

awaiting reviewupdated view markdown ->

Errors come from five layers, and each has its own envelope. Read the layer first, then the code. error_description and message are for humans and may change; error, code and retryable are the control-flow fields.

Layer Where it appears Shape
Discovery validation The conformance/attestation validator, not an agent call Exit code plus errors, warnings, conformance, attestation
MCP transport POST /mcp before a tool runs HTTP status plus a JSON-RPC error object
MCP tools Inside a tool result HTTP 200 with isError: true and the tool error envelope
Provider handshake The provider's agent_signup response error, optional error_description, optional retryable
Broker APIs and OAuth /api/broker/*, /api/oauth/* HTTP status plus {error, error_description, code} where a client branches

The tool error envelope, returned as text content with isError: true:

{
  "error": {
    "code": "rp_unverified",
    "message": "The relying party is not verified and the human owner's policy requires verification.",
    "retryable": false,
    "side_effects": {
      "acceptance_recorded": false,
      "acceptance_created": false,
      "ledger_email_sent_to_agent": false,
      "ledger_email_forwarded_to_human": false,
      "rp_verification_recorded": false,
      "rp_verification_reused": false,
      "assertion_minted": false
    },
    "next_step": "Ask the human owner to change the RP policy or use a verified provider. Nothing was minted.",
    "docs": "agentregistrar://docs/error-recovery"
  }
}

side_effects reports what the failed call actually did. It is the difference between "retry safely" and "retry and duplicate a legal event", so read it before retrying anything with a side effect.

Discovery and verification

The validator is a producer tool, not an agent-facing error surface. It reports two verdicts and an exit code:

Exit Meaning Next action
0 The document was fetched, parsed, and is conformant; no required verification failed. Warnings do not change the code. Publish. attestation.status may still be unverified, expired, or invalid without --require-attestation.
1 A conformance error (including unparseable JSON or a malformed rp_attestation field), or a failed attestation under --require-attestation. Read errors and fix the document or credential.
2 The run could not obtain what it needed: document read/fetch failure, or JWKS unavailable under --require-attestation. conformance is not evaluated. Fix hosting, the URL, the timeout, or the JWKS, then re-run.

A malformed rp_attestation field is a conformance error with attestation.status: "not_checked", never invalid. An absent credential is unverified, never invalid. See the validator guide.

MCP transport and gate errors

These arrive with a non-200 HTTP status from POST /mcp, before any tool runs. The JSON-RPC id is null.

Code HTTP Retryable Meaning Next action
-32001 401 no Bearer token missing, invalid, expired or revoked. The response carries WWW-Authenticate with resource_metadata and scope. Re-run the harness OAuth step, then retry. Do not retry the same token.
-32003 403 no Human owner suspended, or the Master Agent Delegation agreement is unsigned. The human fixes the account in the portal. Retrying cannot succeed.
-32000 406 no The request did not accept text/event-stream (a GET without an SSE Accept header). Use POST with Accept: application/json, text/event-stream.

The three codes are broker implementation details, not part of agent-identity-v1. The stable part is the HTTP status and the WWW-Authenticate challenge.

MCP tool errors

A tool failure is a successful JSON-RPC call: HTTP 200, a result object with isError: true, and the envelope above. Every tool uses the same code set. retryable and next_step are part of the envelope; the table repeats them for lookup.

Code Tools Retryable Meaning Next action
human_suspended identity tools no Human owner account is suspended. The human reactivates the account in the portal.
human_email_unverified identity tools no Human owner email is not verified. The human verifies the email, then retry.
master_tos_unsigned identity tools no The Master Agent Delegation agreement is unsigned. The human completes onboarding and signs it.
agent_revoked all tools no The agent is revoked or operator-suspended. identity_record_signup still records historical proofs for a revoked agent. The human reviews a revocation in the portal. An operator suspension is operator-only to restore. Do not retry or create a replacement silently.
scope_not_granted identity and inbox tools no The agent lacks tos:accept, inbox:read, inbox:send, or one entry of requested_scopes. Check identity_whoami; request only delegated scopes.
tos_text_hash_mismatch identity_signup, identity_prove no accepted_tos_text does not hash to the published/accepted hash. No side effect occurred. Re-fetch terms.text, recompute, send the exact text.
tos_hash_mismatch identity_signup, identity_prove no The accepted terms hash does not match the discovery document. Hard stop: re-discover, re-read, re-accept.
discovery_unreachable identity_signup, identity_prove yes The discovery document could not be fetched. Nothing was minted. Retry the same call; the broker refetches.
discovery_invalid identity_signup, identity_prove no The discovery document failed validation or its signup endpoint is not fetchable. Ask the provider to fix discovery.
protocol_unsupported identity_signup, identity_prove no protocol is not agent-identity-v1. Stop; the service is not supported.
issuer_not_allowed identity_signup, identity_prove no The broker is not in the provider's issuer_allowlist. Stop; this broker is not accepted by the provider.
discovery_source_not_allowed identity_signup, identity_prove, identity_record_signup no A forbidden or mixed discovery/attestation source was supplied, or a require policy rejected agent_supplied_discovery. Use identity_signup with service, or supply exactly one allowed source.
rp_unverified identity_signup, identity_prove no No attestation, and policy is require. Ask the human owner to change policy or use a verified provider.
rp_attestation_invalid identity_signup, identity_prove, identity_record_signup no The attestation failed parse, signature, claims, origin, audience, or key binding, or the exact historical attestation is unavailable. Use the exact attestation; never substitute a newer one.
rp_attestation_expired identity_signup, identity_prove no The attestation is past exp plus 60 seconds. Use a current attestation or a non-gated policy.
rp_broker_untrusted identity_signup, identity_prove, identity_record_signup no The attestation iss is outside the effective trust list. No JWKS fetch was made. Ask the human owner to review the broker trust list.
rp_broker_unavailable identity_signup, identity_prove, identity_record_signup yes A transient broker metadata/JWKS outage. Nothing was written. Retry later. Do not downgrade to unverified.
rp_suspended identity_signup, identity_prove no The attestation or local provider status is suspended. Stop; the provider is suspended.
rp_blocked identity_signup, identity_prove no The human policy is block. The human changes the policy if intended.
ledger_email_failed identity_signup, identity_prove yes The acceptance is recorded; the ledger email dispatch did not finish. Retry the same call. Only mail is retried; no new acceptance.
signup_token_invalid identity_record_signup no The receipt failed signature, typ, audience, claim, historical-window, or conflict checks, or it is a legacy broker-signed token. Obtain an RP-signed v1.2 receipt and the exact historical attestation. Do not retry the rejected token.
signup_token_not_linked identity_record_signup no The receipt references an acceptance this broker has not recorded for that agent/audience. Call identity_signup or identity_prove first.
signup_token_ownership_mismatch identity_record_signup no The receipt belongs to another agent or human owner. Stop. Use the receipt issued for this authenticated agent.
message_not_found inbox_read no No message with that id for this agent. Use an id from inbox_list/inbox_wait_for_email.
wait_timeout inbox_wait_for_email yes Nothing matched within the wait budget. Widen the lookback or wait again with a longer budget. Do not poll tightly.
send_failed inbox_send yes The mail provider rejected or did not accept the message. Nothing was sent or recorded. Retry; nothing left the broker.
internal_error all tools yes Unexpected broker, database, or issuance failure. Retry with the same inputs after reading side_effects.

unverified is not invalid. Absence of the optional credential is a complete, honest verification result; only require refuses it. A suspended agent returns agent_revoked with a suspension-specific message and next step; there is no agent_suspended code.

Reading side_effects

Tool Keys
identity_signup, identity_prove acceptance_recorded, acceptance_created, ledger_email_sent_to_agent, ledger_email_forwarded_to_human, rp_verification_recorded, rp_verification_reused, assertion_minted (seven keys; assertion_minted appears on errors)
identity_register, identity_whoami {} (nothing happened)
identity_record_signup signup_recorded, signup_upgraded, rp_verification_recorded, conflict_flagged
inbox_read, inbox_list, inbox_wait_for_email {}
inbox_send email_sent, message_recorded

identity_signup/identity_prove report all seven keys on gate, discovery, policy, and issuance failures, so an all-false block is positive evidence that no acceptance was written. An unexpected catch-all internal_error may report {}.

Inbox errors

The three inbox-specific codes are in the tool table above; this section adds the operational detail.

Code Retryable What to check Do not
message_not_found no The id belongs to this agent, and the message still exists. Reuse an id from another agent's inbox.
wait_timeout yes from_contains, subject_contains, since_seconds_ago, and whether the sender used the agent address. Poll in a tight loop, or assume the mail will never arrive.
send_failed yes The mail provider status in message. Nothing was sent. Resend blindly after a success response; inbox_send is not idempotent.

inbox_send also reports internal_error when the email left the broker but the ledger insert failed; side_effects.email_sent is true there. Check inbox_list before sending again.

Provider handshake errors

The provider returns these from POST endpoints.agent_signup. The envelope is error, optional error_description, optional retryable; the mapping is fixed for v1. When retryable is absent, infer it from the code.

Code HTTP Retryable Meaning Next action
invalid_request 400 no Malformed headers or body. Fix the request.
invalid_assertion 401 no Signature or shape verification failed. Mint a new assertion.
issuer_not_allowed 403 no iss is not in the provider's issuer_allowlist. Stop. This broker is not accepted by that provider.
audience_mismatch 403 no aud does not equal the provider's audience. Re-discover and mint for the correct audience.
assertion_expired 401 no exp passed beyond the allowed clock skew. Mint a new assertion.
assertion_replayed 409 no The jti was used in a conflicting context. Mint a new assertion.
tos_hash_mismatch 409 no The accepted terms hash is stale or wrong. Re-discover, re-read, re-accept, re-prove.
insufficient_scope 403 no delegation.scopes misses a required_scopes entry. Ask the human to re-delegate.
human_unverified 403 no human.verified is not true. Complete human verification.
rate_limited 429 yes The caller is throttled. Back off, then retry.

A jti repeated for the same agent, account and service is not a replay. The provider resolves it idempotently, usually with resolution: "resolved". assertion_replayed is reserved for a conflicting context. The normative table is spec section 7.2.

Provider API and Contract F/D.2 errors

Provider-facing routes and the authenticated RP routes use {error, error_description, code}.

Code HTTP Route Meaning
invalid_api_key 401 /api/provider/v1/* Missing, malformed, revoked, or unknown provider API key.
insufficient_provider_scope 403 provider API The key lacks the required scope (account:read, keys:write, attestation:read, attestation:write).
provider_suspended 403 provider mutations The provider account is suspended or revoked.
provider_not_eligible 403 attestation issuance The plan/entitlement, origin, or key prerequisite is not met. Free is conformant but cannot issue.
audience_conflict / origin_conflict 409 origin registration The origin or audience is already registered. Goes to operator review.
key_exists / key_limit_reached / last_active_key / key_not_active / no_active_key 409 key routes Frozen key-lifecycle errors. At most 8 active+retiring keys.
challenge_expired / challenge_consumed 410 challenge routes The challenge TTL passed or it was already used.
challenge_failed / pop_invalid 422 origin/key proof The challenge proof failed, or the key PoP is invalid.
invalid_jwk / purpose_mismatch 400 key registration The public JWK is invalid, or purposes are not exactly ["receipt","abuse"].
attestation_not_found 404 status/GET attestation Unknown attestation jti or no current attestation.
invalid_attestation 401 Contract F/D.2 The attestation failed parse/signature/claims/binding.
rp_broker_untrusted 401 Contract F/D.2 The attestation iss is outside the effective trust list. Checked before JWKS.
attestation_not_valid_at_signing 401 Contract F The receipt iat/signed_up_at is outside the named attestation window.
attestation_unavailable 401 Contract F The exact historical attestation is not retrievable and no snapshot exists.
invalid_signup_token 401 Contract F The receipt parse/signature/claims failed. The legacy sanitized body is preserved.
signup_conflict 409 Contract F Same receipt jti with a different body.
unauthenticated_report 401 D.2 A legacy unsigned abuse body. Use the signed {rp_attestation, report} form.
rate_limited 429 Contract F/D.2/provider Bounded ingestion or request rate exceeded.
rp_broker_unavailable 503 Contract F/D.2 Transient trusted-broker metadata/JWKS outage; retryable, no write.

OAuth, DCR and broker API errors

These use the RFC 6749 error field or a broker-specific one. They are HTTP-level failures, not tool results.

Code HTTP Endpoint Meaning Next action
invalid_client_metadata 400 /api/oauth/register Invalid JSON or client metadata. Fix the registration body.
invalid_redirect_uri 400 /api/oauth/register, authorize decision A redirect URI is not loopback HTTP or HTTPS, or does not match the client. Register the exact URI you use.
invalid_client 400 /oauth/authorize, decision The client_id cannot be resolved. Register the client or fix the id.
unsupported_response_type 400 authorize response_type is not code. Use response_type=code.
invalid_request 400 authorize, token, broker APIs, webhook Malformed request or schema failure. Fix the request.
unauthorized 401 authorize decision No human session. Sign in, then approve.
access_denied 403 authorize decision Human suspended, or the human denied the request. Do not retry; the human decides.
email_verification_required 403 authorize decision accept_master_tos was set but the email is unverified. Verify the email first.
master_tos_required 400 authorize decision The Master ToS is unsigned and was not accepted in the decision. Sign it in onboarding or the consent card.
invalid_grant 400 /api/oauth/token Code unknown/expired/used, PKCE mismatch, refresh token unknown/revoked, human inactive/unsigned. Restart the authorization flow.
unsupported_grant_type 400 /api/oauth/token Grant type is not authorization_code or refresh_token. Fix the request.
server_error 500 OAuth endpoints The broker could not persist the client, code or token. Retry later; do not loop.
invalid_webhook_signature 401 /api/webhooks/resend Missing or invalid provider webhook signature. Operator only; fix the webhook secret.

Decision table

Situation Do not Do
tos_hash_mismatch or tos_text_hash_mismatch Retry the same assertion or text Re-discover, re-read terms.text, re-accept, re-prove
rp_unverified under require Treat the provider as invalid Ask the human to change policy or use a verified provider
rp_attestation_expired Reuse the expired attestation Renew/publish a current attestation, or use a non-gated policy
rp_broker_unavailable Downgrade to unverified or retry tightly Retry later; the gate fails closed
rp_suspended / rp_blocked Retry Stop; the provider or policy is blocking
discovery_source_not_allowed Pass a discovery document to identity_signup Call identity_signup with service; or identity_prove with exactly one allowed source
assertion_expired Reuse the JWT Mint a new assertion
assertion_replayed Retry blindly Confirm the same-context idempotent path; otherwise mint new
ledger_email_failed Assume the acceptance was lost Retry; the acceptance is recorded and only mail re-sends
signup_token_invalid Substitute a newer attestation or a legacy token Use the RP-signed v1.2 receipt with the exact historical attestation
Inbox wait_timeout Poll in a tight loop Use a longer timeout or narrower filter
Lost provider credential Re-run signup Use the provider recovery path in the context guide
agent_revoked Retry or register a replacement silently Tell the human; they review the agent in the portal
-32001 on /mcp Retry the same token Re-run the harness OAuth step

Verification record

The v1.2 code names and retryability were checked against the shared McpToolErrorCodeSchema, the RP verification mapping, the Contract F/D.2 handlers, and the provider route errors at broker commit 5e57ecf on 2026-10-24. This page does not claim a live deployment of the v1.2 broker; live error responses are part of the release verification gate.

sections

type to search.

up/down navigateenter selectesc close