guard, guard_identity, and verify_request return it as a decision that carries the exact response to send back. ZCError is reserved for what the caller got wrong (malformed input) or what the environment did (the ZeroClick API being unreachable or answering nonsense).
Decisions or exceptions, by operation
GuardResult documents the deny reasons that ride on decisions; this page covers the exceptions.
ZCError
ZCError(code, message=None, operation=..., **context) carries a stable machine code, the operation that raised it, and a context dict. The dict holds the operation plus code-specific keys such as status, reason, kid, or meter_slug. str(error) is a human-readable message; branch on code and context, never on the message text.
is_zc_error(error, code=None) returns True when error is a ZCError, optionally of a specific code. It is useful at boundaries that catch broadly:
Error codes
ZCErrorCode is a Literal of five values:
The allowance outage policy
Insideguard, after a signature has verified, the codes api_transport_error, api_status_error, and api_response_invalid all mean the same thing: the allowance API gave no usable answer. The SDK routes these three, and only these, to the client’s allowance_unavailable_policy instead of propagating them: "allow" serves the request with allowance == "unavailable", "deny" returns the SDK’s 503 {"error":"allowance_unavailable"}, and "throw" re-raises the error for your application. The on_allowance_unavailable hook sees the error first, whatever the policy.
The policy never applies to a missing or invalid signature, and an allowed: false answer is not an outage: it is a 402 denial. Outside guard, in check_allowance and report_usage, these codes always raise. See configuration for choosing a policy.
Handling api_status_error
api_status_error carries the HTTP status in error.context["status"]. When the API rejects a report_usage call with a typed status (402, 404, or 409), its machine reason also rides in error.context["reason"]: the report endpoint answers 402 for access_inactive, plan_expired, and usage_exhausted, 409 for meter_not_priced, and 404 otherwise. The errors reference covers the platform-wide error model.
idempotency_key, so replaying the same report can never double-bill.
Encryption error codes
decrypt_request and encrypt_response raise ZCError with JWE-specific string codes that sit outside the five-value ZCErrorCode literal. Compare error.code directly rather than through is_zc_error’s typed code parameter:
private_key_not_found, private_key_resolution_failed, and decryption_failed carry the JWE’s kid in error.context.