Errors — Grep API v2

Errors

Structured error envelope and the full code registry. Plus the difference between 402 insufficient_credits and 429 rate_limited.

Error envelope

Every v2 error response shares the same shape — an error object with a stable code, a human-readable message, optional structured details, and a request_id for support escalation.

json
{
  "error": {
    "code": "validation_error",
    "message": "Field 'question' must be a non-empty string.",
    "details": {
      "field": "question",
      "received": ""
    },
    "request_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
  }
}
  • code Stable, machine-readable string. Switch on this in your error handler — never the message.
  • message Human-readable description. Safe to log; not safe to surface to end-users without translation.
  • details Optional structured payload. Shape varies by code — for validation_error it's the offending field and value.
  • request_id Unique per request. Quote this in any support ticket — we can find the trace from this alone.

Code registry

Every code we emit, what it means, and the HTTP status it travels on.

HTTPCodeMeaning
400invalid_requestThe request was malformed (bad JSON, missing required field, wrong content-type).
401unauthenticatedYour API key is missing, malformed, or revoked.
402insufficient_creditsYour tenant ran out of credits. Top up before retrying.
403forbiddenYour key is valid but lacks permission for this resource (often a tenant mismatch).
404job_not_foundNo job exists with that ID — or it belongs to another tenant and you can't see it.
404resource_not_foundGeneric not-found for non-job resources (apps, transactions, etc.).
409conflictIdempotency key collision, body-hash mismatch, or in-flight key reuse. See the idempotency guide.
422validation_errorRequest shape is fine but a field value is invalid (e.g. effort='warp_speed').
429rate_limitedToo many requests in the rate-limit window. Back off and retry.
500internal_errorServer-side bug. Quote the request_id in a support ticket.
503upstream_unavailableAn upstream service (data provider, MCP tool) is degraded. Usually transient — retry.

402 insufficient_credits vs 429 rate_limited

Both prevent your request from succeeding, but they mean different things and require different handling. Don't conflate them.

402 insufficient_credits

402 — out of credits

Your tenant has zero credits remaining. Backing off and retrying won't help — top up the account or contact your admin. The X-Grep-Credits-Remaining header will be 0.

429 rate_limited

429 — too many requests

You're sending requests faster than your rate limit allows. Back off using the Retry-After header and retry. Credits aren't depleted — this is purely about request frequency.

Pro tip: switch on code, not status

Two different error codes can travel on the same HTTP status (e.g. 404 covers both job_not_found and resource_not_found). Always branch on error.code in your client — it's the stable contract.