Error Codes
All INK endpoints MUST return structured error responses:
{ "protocol": "ink/0.1", "error": true, "code": "signature_verification_failed", "message": "Ed25519 signature did not verify against any authoritative candidate key"}Error Codes
The codes below cover both the transport-auth middleware (returned by verifyInkAuth
in the library) and application-layer rejections that an
integrator may add on top.
Transport authentication (returned by verifyInkAuth)
| Code | HTTP Status | Description |
|---|---|---|
missing_authorization | 401 | No Authorization header present |
invalid_auth_scheme | 401 | Header is not a valid INK-Ed25519 <sig> form |
missing_sender | 401 | body.from is empty or missing |
invalid_from_field | 401 | body.from is not a string, or exceeds 256 chars |
missing_timestamp | 401 | body.timestamp is missing |
invalid_timestamp | 401 | body.timestamp does not parse as a valid date |
timestamp_expired | 401 | Timestamp older than 5 minutes |
timestamp_too_far_future | 401 | Timestamp more than 30 seconds ahead |
signature_verification_failed | 401 | Signature did not verify against any authoritative candidate key |
invalid_signature | 401 | Signature failed verification against the bootstrap public key |
unresolvable_sender_key | 401 | Could not derive or look up a public key for the sender |
nonce_handling_required | 401 | Middleware was invoked without a nonceStore option (fail-closed default) |
missing_nonce | 401 | body.nonce missing or outside [16,256] charset bounds when middleware-side nonce enforcement is on |
nonce_replay | 401 | Nonce already recorded in the NonceStore within the freshness window |
nonce_store_error | 401 | nonceStore.has or nonceStore.add threw (fail-closed) |
Application-layer / extension errors
| Code | HTTP Status | Description |
|---|---|---|
duplicate_nonce | 400 | Returned by the standalone checkReplay helper when a nonce is in previouslySeenNonces |
encryption_required | 400 | Intent type requires encrypted payload |
decryption_failed | 400 | Could not decrypt payload |
unsupported_version | 400 | Protocol version not supported |
rate_limited | 429 | Too many requests |
handshake_budget_exhausted | 429 | Per-correlation handshake budget exceeded |
sender_rate_limited | 429 | Per-sender sliding window rate limit exceeded |
transport_scope_violation | 403 | Invocation transport not permitted by delegation token |
sender_mismatch | 403 | Message from field does not match authenticated sender identity |
access_denied | 403 | Requester is not a party to the referenced message |
internal_error | 500 | Agent internal error |
DID resolution and agentLink lookup are integrator-side concerns. If your
implementation surfaces those failures, conventional codes are
unknown_did (404) and no_agent_link (404).
Witness Service Error Codes
The witness service returns these additional error codes on its authenticated endpoints.
| Code | HTTP Status | Description |
|---|---|---|
missing_authorization | 401 | No Authorization header present |
invalid_auth_scheme | 401 | Authorization header is not INK-Ed25519 scheme |
nonce_replay | 401 | Nonce has already been used (10-minute window) |
duplicate_event_id | 409 | An event with this ID has already been recorded |
invalid_agent_signature | 400 | Event agentSignature does not verify against the agent’s public key |
invalid_agent_id_format | 400 | Cannot extract a public key from the agentId field |
sender_mismatch | 401 | Transport auth sender does not match body.from |
event_agent_mismatch | 400 | event.agentId does not match submission sender |
rate_limit_exceeded | 429 | Agent has exceeded 30 submissions per minute |
forbidden | 403 | Requester is not a party to the queried message |