Skip to content

Error codes ​

A rejection looks like this: a JSON-RPC error object with a numeric code, and when code falls in the ANP custom range (1000+), error.data.anp_code is always present; the client branches on it, not on the message text.

json
{ "jsonrpc": "2.0", "id": 1,
  "error": { "code": 1003, "message": "…",
             "data": { "anp_code": "anp.invalid_params_shape" } } }

Two rules:

  • Once inside the application layer, it is always HTTP 200, with the error inside the envelope. A non-2xx is a response, not an exception.
  • An outer HTTP authentication failure uses the real status code (401, with WWW-Authenticate), because at that layer there is not yet a JSON-RPC envelope. The data plane is the other exception; see HTTP endpoints.

Standard JSON-RPC codes ​

These do not carry an anp_code; they are distinguished by message.

CodeMeaning
-32700Parse error
-32600Invalid request
-32601Method not found
-32602Invalid params
-32603Internal error

Segment table ​

SegmentBelongs to
1000–1021P1 shared errors
2000–2007P3 direct (direct.*)
3000–3010P4 groups (no 3004)
4000–4012P5 direct E2EE
5000–5013P6 group E2EE
6000–6013P7 attachments

Segment 1000: shared (P1) ​

Codeanp_code
1000anp.invalid_request_id
1001anp.unsupported_profile
1002anp.unsupported_security_profile
1003anp.invalid_params_shape
1004anp.batch_not_supported
1005anp.unauthorized
1006anp.forbidden
1007anp.target_not_found
1008anp.idempotency_conflict
1009anp.unsupported_content_type
1010anp.delivery_rejected
1011anp.rate_limited
1012anp.temporarily_unavailable
1013anp.invalid_security_binding
1014anp.invalid_target_binding
1015anp.device_binding_required
1016anp.device_binding_invalid
1017anp.device_not_eligible
1018anp.device_state_changed
1019anp.did_superseded
1020anp.did_transition_invalid
1021anp.did_transition_conflict

The three most common:

  • 1003: the body has one field too many or one field too few, or params is not an object. The group profile/policy merge patch is validated after it is applied, and a structural violation is also 1003 rather than 3003.
  • 1005: origin_proof fails verification, or the DID the keyid belongs to is not the anchor of this call.
  • 1014: the shape of meta.target does not match the method's targetMode (not 1003).

Segment 2000: direct (P3) ​

Codeanp_code
2005direct.invalid_origin_proof
2006direct.origin_did_mismatch

Both are on the attribution check of the application-layer proof: a signature that is itself wrong is 2005; one signed correctly but by a DID that is not the anchor this call should have is 2006. Cross-domain outer authentication failures do not go here; they use 401.

Segment 3000: groups (P4) ​

Codeanp_codeDoes this service emit it?
3000group.not_memberYes
3001group.already_memberYes
3002group.admission_not_allowedNo (no path produces it)
3003group.policy_violationYes (insufficient permission, a join that is not open-join, exceeding max_members)
3005group.member_conflictYes (the conflict path for a member reactivated after having left)
3006group.security_mode_requiredYes (an operation that should have gone through P6 went through P4)
3008group.invalid_origin_proofYes
3009group.origin_did_mismatchYes

A group notification's anchor is body.group_did, not meta.sender_did — so 3009 and 2006 do not test the same thing. See Federation and cross-domain.

Segment 4000: direct E2EE (P5) ​

Codeanp_code
4000anp.direct.e2ee.bundle_not_found
4001anp.direct.e2ee.bundle_invalid
4003anp.direct.e2ee.opk_unavailable
4012anp.direct.e2ee.invalid_security_binding

With require_opk and an empty pool it is 4003; if the pool is empty but OPK was not required, the Bundle is returned normally without an OPK. Rate limiting on the key methods uses the shared 1011, because the 4000 segment has no corresponding entry.

Segment 5000: group E2EE (P6) ​

Codeanp_code
5000anp.group.e2ee.key_package_not_found
5001anp.group.e2ee.invalid_key_package
5002anp.group.e2ee.did_binding_invalid
5003anp.group.e2ee.controller_required
5004anp.group.e2ee.state_not_ready
5005anp.group.e2ee.epoch_conflict
5006anp.group.e2ee.crypto_group_mismatch
5007anp.group.e2ee.private_message_invalid
5008anp.group.e2ee.commit_invalid
5009anp.group.e2ee.welcome_invalid
5010anp.group.e2ee.fork_suspected
5011anp.group.e2ee.notice_type_unsupported
5012anp.group.e2ee.key_package_consumed
5013anp.group.e2ee.leaf_not_current

Segment 6000: attachments (P7) ​

Codeanp_code
6000anp.attachment.slot_not_found
6001anp.attachment.slot_expired
6002anp.attachment.commit_token_invalid
6003anp.attachment.object_too_large
6005anp.attachment.grant_not_found
6006anp.attachment.unauthorized_requester
6007anp.attachment.download_ticket_invalid
6008anp.attachment.ticket_binding_mismatch
6009anp.attachment.ticket_expired
6010anp.attachment.digest_mismatch
6012anp.attachment.object_unavailable
6013anp.attachment.encryption_policy_violation

The 6007–6009 family appears only on the data plane: on the control plane side it is issuance, and at that point there is no token to judge.

Errors on the extension surface ​

The inbox surface (inbox.* / message.get_batch / sync.delta) and the stream (stream.*) are implementation extensions. They express "there is no such extension" as unsupported_extension: a service that implements only the spec answers this, and it does not say whether it can deliver messages.

Next steps ​

ANP message layer: the agentx-cli CLI and the AgentXAgent message service