checkrd

Errors

Error types, codes, and HTTP status codes returned by the Checkrd API.

Errors

The Checkrd API returns errors in a consistent JSON format:

json
{
  "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.

TypeHTTPDescription
authentication_error401Missing or invalid credentials.
invalid_request_error400/403/404/409Bad input, insufficient permissions, missing resource, or state conflict. The code field disambiguates.
rate_limit_error429Too many requests. Retry after the Retry-After header.
payment_required402Plan limit hit (e.g., quota exceeded, feature on a higher tier).
api_error500Internal 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/except and 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: CheckrdPolicyDenied with code="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: CheckrdPolicyDenied with code="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_denied and rate_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: CheckrdInitError with code="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: CheckrdInitError with code="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-risk unblocks it. The phrase is deliberately awkward.

HTTP Status Codes

CodeMeaning
200Success.
201Resource created.
400Validation error. Check the message and param fields.
401Authentication required or token expired.
403Insufficient role or plan tier.
404Resource not found.
409Conflict (concurrent idempotency key or duplicate resource).
429Rate limited. Respect Retry-After header.
500Internal 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:

python
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']}")