{"slug": "keep-the-http-status-and-json-error-code-separate-in-your-ai-api-adapter", "title": "Keep the HTTP status and JSON error code separate in your AI API adapter", "summary": "A developer published an offline Python helper that keeps an API response's HTTP status separate from any numeric error code found in the JSON body, so adapters can distinguish a transport-level 402 from a code embedded in the payload. The function, which makes no network calls, returns only the HTTP status, a validated 100–599 JSON code, a UUID-shaped request ID, and a body-kind label, deliberately omitting error messages, prompts, and authorization headers. The writeup also advises against automatically changing spending caps on a generic billing label and recommends including timestamp, endpoint, status, and request ID when escalating issues.", "body_md": "An adapter label such as `provider_rejected_402` leaves an important question unanswered: did the server send HTTP 402, or did the adapter find 402 inside a JSON body?\n\nThose are different observations. If the adapter merges them, the next person debugging the request has to guess what actually happened.\n\nFor an error response, start with four fields:\n\nRouterBase's [error reference](https://docs.routerbase.com/essentials/errors) documents both nested and top-level JSON error shapes, along with `x-request-id` for correlating a request. Keep the transport status in its own field rather than replacing it with a value from the body.\n\nThis function summarizes response data you supply. It makes no network requests and needs no API key. The example response is synthetic.\n\n```\n\"\"\"Offline example: summarize a supplied error response; never call an API.\"\"\"\n\nimport json\nfrom uuid import UUID\n\ndef summarize_error(http_status, headers, body):\n    payload = {}\n    body_kind = \"too_large\"\n    if len(body) <= 65536:\n        try:\n            value = json.loads(body)\n            body_kind = \"object\" if isinstance(value, dict) else \"non_object\"\n            if isinstance(value, dict):\n                payload = value\n        except (ValueError, RecursionError):\n            body_kind = \"invalid_json\"\n\n    error = payload.get(\"error\")\n    fields = error if isinstance(error, dict) else payload\n    code = fields.get(\"code\")\n    if isinstance(code, str) and code.isascii() and code.isdigit() and len(code) == 3:\n        code = int(code)\n    if type(code) is not int or not 100 <= code <= 599:\n        code = None\n\n    normalized = {name.lower(): value for name, value in headers.items()}\n    request_id = normalized.get(\"x-request-id\") or payload.get(\"request_id\")\n    try:\n        request_id = str(UUID(request_id)) if isinstance(request_id, str) else None\n    except ValueError:\n        request_id = None\n\n    return {\n        \"http_status\": http_status,\n        \"json_numeric_code\": code,\n        \"request_id\": request_id,\n        \"body_kind\": body_kind,\n    }\n\nif __name__ == \"__main__\":\n    print(summarize_error(\n        402,\n        {\"X-Request-ID\": \"00000000-0000-4000-8000-000000000001\"},\n        '{\"error\":{\"code\":402,\"message\":\"Synthetic example\"}}',\n    ))\n```\n\nThe output keeps `http_status` and `json_numeric_code` as separate values. In the synthetic example both are 402. If you supply HTTP 200 and a body containing `{\"code\":402}`, it preserves both values; that is an adapter test case, not a claim that RouterBase returns that combination.\n\nThe function deliberately omits error messages, prompts, request bodies, and authorization headers. It accepts only numeric codes in the 100–599 range and UUID-shaped request IDs. String error categories are left out of this small example. A missing value remains `None`; it is not replaced with a guessed cause.\n\nThis is a limited diagnostic summary, not a general redaction system or a complete response validator. Pass the actual integer status from your HTTP client, string header names and a text body. Bound the response read in your HTTP client too: the length check here happens after the body has reached the function.\n\nFor RouterBase organization requests, the [organization guide](https://docs.routerbase.com/essentials/organizations) describes 402 responses for an insufficient organization wallet and for member spending limits. The HTTP status alone does not distinguish those cases. Read the specific error in a protected debugging context, then check the relevant account scope and limits.\n\nAvoid making automatic changes to spending caps just because an adapter emitted a generic billing label. Likewise, a successful catalog lookup does not validate a later generation request.\n\nWhen escalating an issue, include the timestamp with its time zone, endpoint path, HTTP status, and request ID. Review any error text separately before sharing it. Keep credentials and private inputs out of a public support message.\n\nUse a nested error object, a top-level numeric code, an HTML error page, a JSON array, and an oversized body. Verify that a mismatch between transport status and body code stays visible.\n\nWe checked this example locally with synthetic inputs, including malformed JSON and an invalid request ID. No inference request was sent, and no model performance or billing behavior was tested.\n\nWe are the RouterBase team. Explore [RouterBase](https://routerbase.com/?utm_source=dev&utm_medium=article&utm_campaign=2026_11_error_evidence&utm_content=rb_20261102_error_evidence_dev_v01) for an OpenAI-compatible API for AI models.", "url": "https://wpnews.pro/news/keep-the-http-status-and-json-error-code-separate-in-your-ai-api-adapter", "canonical_source": "https://dev.to/routerbase_com/keep-the-http-status-and-json-error-code-separate-in-your-ai-api-adapter-j7p", "published_at": "2026-11-02 03:45:58+00:00", "updated_at": "2026-11-02 03:52:04.711600+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-infrastructure"], "entities": ["RouterBase"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/keep-the-http-status-and-json-error-code-separate-in-your-ai-api-adapter", "markdown": "https://wpnews.pro/news/keep-the-http-status-and-json-error-code-separate-in-your-ai-api-adapter.md", "text": "https://wpnews.pro/news/keep-the-http-status-and-json-error-code-separate-in-your-ai-api-adapter.txt", "jsonld": "https://wpnews.pro/news/keep-the-http-status-and-json-error-code-separate-in-your-ai-api-adapter.jsonld"}}