Errors
Error types, codes, and HTTP status codes returned by the Checkrd API.
Errors
The Checkrd API returns errors in a consistent JSON format:
{
"error": {
"type": "invalid_request_error",
"code": "parameter_missing",
"message": "Name is required.",
"param": "name"
}
}Error Types
The type field is one of five values. Authorization, not-found, and conflict cases all surface as invalid_request_error with a more specific code.
| Type | HTTP | Description |
|---|---|---|
authentication_error | 401 | Missing or invalid credentials. |
invalid_request_error | 400/403/404/409 | Bad input, insufficient permissions, missing resource, or state conflict. The code field disambiguates. |
rate_limit_error | 429 | Too many requests. Retry after the Retry-After header. |
payment_required | 402 | Plan limit hit (e.g., quota exceeded, feature on a higher tier). |
api_error | 500 | Internal server error. Contact support if persistent. |
Common code values: parameter_missing, invalid_value, invalid_json_body, insufficient_role, resource_not_found, idempotency_key_in_use, cannot_delete_last_org, org_count_exceeded, plan_limit_exceeded, feature_not_available.
SDK error codes
The SDKs raise typed exceptions whose code field matches the values
below. Every code has a deep-link page at
https://checkrd.io/errors/{code} that redirects here for context.
policy_denied
A policy rule explicitly denied the request, or the default-deny branch fired with no matching allow rule.
- Surfaces as:
CheckrdPolicyDenied(Python) /CheckrdPolicyDenied(JavaScript), thrown from inside the HTTP transport before the request leaves the machine. - Carries:
rule_name,reason,request_id,url,dashboard_url,suggestion. - Fix: Edit the matching rule in your policy YAML, or — if the
deny is correct — wrap the call in
try/exceptand handle it as business logic. See Error handling for the three recommended patterns.
rate_limit_exceeded
A rate-limit rule in the active policy denied the request because the configured window quota was exhausted.
- Surfaces as:
CheckrdPolicyDeniedwithcode="rate_limit_exceeded". - Carries: the rate-limit rule name, current window utilization, retry hint.
- Fix: Either back off and retry (the SDK exposes the retry hint), or raise the limit in your policy YAML. Rate-limit windows are sliding and bounded at 10K keys per agent.
kill_switch_active
The agent's kill switch is engaged. Every request is denied with
this code until the switch is released from the dashboard or via
checkrd agents kill-switch off <agent-id>.
- Surfaces as:
CheckrdPolicyDeniedwithcode="kill_switch_active". - Fix: Disengage the kill switch, then retry. The decision flow
evaluates the kill switch before any policy rule, so this code
takes precedence over
policy_deniedandrate_limit_exceeded.
browser_use_detected
The JavaScript SDK was initialized in a browser without
dangerouslyAllowBrowser: true. The default is fail-closed because
the API key and Ed25519 private key would be shipped to end users.
- Surfaces as:
CheckrdInitErrorwithcode="browser_use_detected", thrown synchronously at construction. - Fix: Move the SDK to a server-side proxy (Next.js Route Handler, Hono, Cloudflare Worker, Lambda). See Browser usage for the recommended patterns, and the opt-in flag if you have a legitimate browser use case.
wasm_integrity_skip_in_prod
The SDK was started with CHECKRD_SKIP_WASM_INTEGRITY=1 set, and
the host environment looked like production (one of 11 framework
markers including NODE_ENV=production, KUBERNETES_SERVICE_HOST,
AWS_EXECUTION_ENV, VERCEL).
- Surfaces as:
CheckrdInitErrorwithcode="wasm_integrity_skip_in_prod". - Fix: Drop the env var. The flag exists for source-checkout
development where the recorded WASM hash hasn't been regenerated;
it should never be set in production. If you genuinely need the
bypass for a one-off triage in prod, the additional acknowledgement
CHECKRD_I_UNDERSTAND_WASM_INTEGRITY_RISK=i-understand-the-riskunblocks it. The phrase is deliberately awkward.
HTTP Status Codes
| Code | Meaning |
|---|---|
200 | Success. |
201 | Resource created. |
400 | Validation error. Check the message and param fields. |
401 | Authentication required or token expired. |
403 | Insufficient role or plan tier. |
404 | Resource not found. |
409 | Conflict (concurrent idempotency key or duplicate resource). |
429 | Rate limited. Respect Retry-After header. |
500 | Internal error. The request body is never leaked in error messages. |
Handling Errors
All error responses include a type and message. Use type for programmatic handling and message for display:
import os
import httpx
response = httpx.post(
"https://api.checkrd.io/v1/agents",
headers={
"X-API-Key": os.environ["CHECKRD_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": "create-sales-agent-2026-05",
},
json={"name": "sales-agent"},
)
if response.status_code >= 400:
error = response.json()["error"]
if error["type"] == "rate_limit_error":
retry_after = int(response.headers["Retry-After"])
# wait and retry
elif error["type"] == "invalid_request_error":
print(f"Invalid field: {error.get('param')}: {error['message']}")