code in an error envelope. Program against the code, not the HTTP status — and find yours below.
Signature rejected (401)
replayed_nonce under load on a multi-instance service usually means a per-process nonce cache. §5.6 requires the seen-(keyid, nonce) set to be shared and atomic across every verifier instance. On Cloudflare, use DurableObjectNonceStore, not KvNonceStore, for atomic check-and-set. See Deploy to Cloudflare Workers.Attestation rejected (401)
A common
invalid_attestation cause is an aud mismatch: the agent minted for did:web:api.example.com but the service’s service_did is did:web:example.com. They must be identical.
Claim & ownership (401 / 403 / 409)
Lifecycle (404 / 410)
Rate limited (429)
rate_limit_exceeded from a service and rate_limited from the trust attestor are different things, and neither is a revocation:
- Service
429 rate_limit_exceeded— you hit a per-route limit. Honor theRetry-Afterheader and back off. See Rate limiting. - Attestor
429 rate_limited— you’re minting attestations too fast (the per-binding daily cap). Back off; do not re-link — your binding is fine.
”I revoked, but the agent still works”
Revocation has two levers, each with a deliberate latency (Revocation):- Local revoke at a service is immediate at that service but propagates nowhere else — there’s no global revocation bus (§8.3).
- Global revoke at the attestor stops new attestations, but tokens already minted stay valid until they expire (≤ 15 min). Services that only checked attestation at signup never see it — unless they run attested sessions, which close the gap within the freshness window.
Still stuck?
Error codes
Every reserved code, status, and trigger.
Security model
Why these boundaries exist.