{
  "id": 16433150,
  "title": "4,474 of 5,369 Output Tokens Were Thinking: Reading Claude API Errors",
  "url": "https://urgent.news/2026/10/25/4-474-of-5-369-output-tokens-were-thinking-reading-claude-api-errors",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-25T05:00:22.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/sungwoo_lee_e0f26be4a29fd/4474-of-5369-output-tokens-were-thinking-reading-claude-api-errors-490h"
  },
  "original_language": "en",
  "account": "A peculiar issue arises with the Claude API: receiving an HTTP 200 status code alongside an empty text block. This results in JSON parsers reporting no JSON found, despite no error being thrown or logged. In this scenario, 4,474 out of 5,369 output tokens were allocated to thinking, leaving only 895 tokens for the actual response. The triage process for handling such failures now involves retrying, fixing the request, or waiting.\n\nAll API errors are returned in the same JSON format: a top-level error object containing a type and a message, along with a request_id. The classification should be based on the error.type, not the message text, as the wording can change over time. SDKs raise distinct exception classes for different status codes, so catching the exception class is essential.\n\nThere are four main error types: 400 (invalid_request_error), 429 (rate_limit_error), 529 (overloaded_error), 500 (api_error), and 504 (timeout_error). Each type requires a specific action: retrying for 400 and 429, waiting and retrying for 529, and backoff or moving long requests to streaming/batch API for 500 and 504.\n\nThe SDK already retries connection errors, 429s, and 5xx responses twice with exponential backoff, respecting the retry-after header. However, if an exception reaches your code, two additional retries are already performed. A 429 can signify a rate limit, monthly spend cap, or Claude Code workspace spend limit. Only the rate limit issue can be resolved by waiting. Mistaking a spend cap for a rate limit can lead to an endless loop of receiving the same 429 error.\n\nSometimes, an increase in organization usage can trigger a 429 due to an acceleration limit. The solution is to gradually increase traffic and maintain even usage patterns. A 400 error on a seemingly valid request occurs when the model drops a parameter. If the payload looks fine, check whether the model dropped a parameter, such as the thinking.type.enabled flag. If the assistant message prefill is not supported by newer models, use structured output or the system prompt instead. When the tool_choice is set to type tool and any are not supported, some models reject forced tool calls. An unexpected 400 error can also arise from passing the temperature parameter, which is not officially documented.\n\nThe most frustrating issue is when the API returns an empty response with an HTTP 200 status code, indicating that the thinking tokens have consumed the entire max_tokens budget. The response text is truncated or missing, and no exception is raised. To diagnose this issue, examine the usage.output_tokens_details.thinking_tokens field. If the output must arrive at a specific time, consider raising the max_tokens value or reducing the effort to minimize thinking token usage. In our case, breaking the task into multiple calls for one outline and one table of contents per post resolved the issue after three failed attempts.",
  "summary": "The most confusing Claude API failure is not a 400, a 429, or a 529. It is an HTTP 200 with an empty text block. Nothing was thrown and nothing was logged as an error, yet your JSON parser reports \"no JSON found\". In our case the cause was thinking tokens eating the whole max_tokens budget: 4,474 of 5,369 output tokens went to thinking, which left 895 for the answer. This post is the triage order…",
  "key_points": [
    "4,474 out of 5,369 tokens allocated to thinking",
    "API returns HTTP 200 with empty text block",
    "Retry, fix request, or wait for failure handling"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}