Concepts

Errors

Structured error shapes returned by the brandRNA REST and MCP APIs.

Every brandRNA error is structured. REST returns a JSON body with HTTP status codes; MCP returns a JSON-RPC error envelope. Your client should never need to scrape error strings — there is always a stable machine- readable code.

REST error shape

All non-2xx REST responses share this shape:

{
  "error": "quota_exceeded",
  "code": "quota_exceeded",
  "details": {
    "tier": "free",
    "monthly_used": 100,
    "monthly_limit": 100,
    "upgrade_url": "https://brandrna.com/pricing"
  }
}
  • error — short snake_case identifier. Stable across versions.
  • code — alias of error for clients that expect a code field.
  • details — error-specific structured context. Always an object (may be empty).

Use error / code to branch your retry logic; surface details to your end-users where appropriate.

4xx vs 5xx semantics

  • 4xx — caller's fault. Don't retry without changing the request. 401 / 403 / 404 / 422 / 429 fall here.
  • 5xx — our fault. Retry with exponential backoff (start at 500ms, double up to 30s, max 5 retries). 500 / 502 / 504 fall here.

Common errors

StatusCodeMeaningTypical causeFix
401invalid_api_keyHeader missing or key not recognised.Mistyped key, revoked key, missing Bearer.Re-copy from dashboard.
403forbidden_resourceAuth OK but resource is off-limits.SSRF guard blocked an internal IP, locked feature.Check the URL is public; contact support if feature-gated.
404not_foundJob, domain, or asset doesn't exist.Wrong job_id, novel domain not yet analysed.Submit POST /analyze first; poll GET /analyze/{job_id}.
422validation_errorRequest body malformed.Bad URL, missing required field.Inspect details.field for offender.
429quota_exceededFree-tier monthly cap hit.Free tier 100 calls/mo or per-IP burst.Upgrade via details.upgrade_url or wait for the next month.
500internal_errorUnexpected server failure.Bug, transient outage.Retry with backoff; report on Discord if persistent.
502scraper_failurePlaywright crashed mid-scrape.Cloudflare interstitial, exotic SPA.Retry; if it persists, the URL likely needs special handling.
504scraper_timeoutScrape exceeded 60s budget.Slow origin, heavy SPA.Retry; increase your client timeout to 120s.

details.upgrade_url is included on 429s so an MCP client (or your own agent) can deep-link the user straight into the upgrade flow without hard-coding URLs.

All of the codes above are stable. We may add new codes in future minor versions, but never rename or repurpose existing ones.

MCP error shape

The MCP server speaks JSON-RPC 2.0. Errors travel in the standard envelope:

{
  "jsonrpc": "2.0",
  "id": "req-42",
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": {
      "field": "domain",
      "reason": "must be a valid hostname"
    }
  }
}

We use the JSON-RPC standard codes plus a brandRNA-specific block. All errors are produced via the McpError factories in app/mcp/errors.py — never hand-rolled — so the shape is uniform across every tool, resource, and prompt the server exposes.

MCP error codes

CodeNameWhen
-32600InvalidRequestMalformed JSON-RPC envelope.
-32601MethodNotFoundTool / method not exposed by this MCP server.
-32602InvalidParamsTool called with bad params (caught by Zod schema).
-32603InternalErrorUnexpected server failure inside a tool.
-32000GenericErrorCatch-all for brandRNA-specific failures.
-32001QuotaExceededEquivalent of REST 429; data.upgrade_url included.
-32002UpstreamScraperFailPlaywright failure surfaced via MCP tool call.
-32003OAuthRevokedToken was revoked mid-session; re-auth required.

The data field carries the same structured context as REST details, so an MCP-aware agent can surface upgrade prompts identically across both surfaces.

What to do on errors

  • 4xx — surface the error to your user; do not auto-retry. The request is wrong, not transient.
  • 5xx — exponential backoff. Cap at 5 retries. Beyond that, consider the dependency degraded and switch to your fallback path.
  • 429 — show details.upgrade_url to the user (or open it in a new tab on click). Don't treat it as a hard error; it's a billing prompt.
  • OAuthRevoked (-32003) — re-run the OAuth dance; the previous token was rotated or rejected.

For ongoing incidents, watch https://status.brandrna.com (status page lands in Phase 8). For real-time triage, our Discord support channel is the fastest route to a human.

What's next

On this page