{"record":{"id":"794b3c26c3385ed3","repo":"can1357/oh-my-pi","slug":"anthropic-thinking-budget-requires-max-tokens-grea","errorCode":null,"errorMessage":"Anthropic thinking budget requires max_tokens greater than ${OUTPUT_FALLBACK_BUFFER}; got ${raisedMaxTokens}","messagePattern":"Anthropic thinking budget requires max_tokens greater than (.+?); got (.+?)","errorType":"exception","errorClass":"ConfigurationError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/providers/anthropic.ts","lineNumber":3174,"sourceCode":"function ensureMaxTokensForThinking(params: MessageCreateParamsStreaming, maxAllowedTokens: number): void {\n\tconst thinking = params.thinking;\n\tif (thinking?.type !== \"enabled\") return;\n\n\tconst budgetTokens = thinking.budget_tokens ?? 0;\n\tif (budgetTokens <= 0) return;\n\n\tconst currentMaxTokens = Math.min(params.max_tokens ?? maxAllowedTokens, maxAllowedTokens);\n\tconst raisedMaxTokens = Math.min(\n\t\tMath.max(currentMaxTokens, budgetTokens + OUTPUT_FALLBACK_BUFFER),\n\t\tmaxAllowedTokens,\n\t);\n\tparams.max_tokens = raisedMaxTokens;\n\n\tif (budgetTokens + OUTPUT_FALLBACK_BUFFER <= raisedMaxTokens) return;\n\n\tconst clampedBudget = raisedMaxTokens - OUTPUT_FALLBACK_BUFFER;\n\tif (clampedBudget <= 0) {\n\t\tthrow new AIError.ConfigurationError(\n\t\t\t`Anthropic thinking budget requires max_tokens greater than ${OUTPUT_FALLBACK_BUFFER}; got ${raisedMaxTokens}`,\n\t\t);\n\t}\n\tthinking.budget_tokens = clampedBudget;\n}\n\nfunction applyCacheControlToLastBlock(blocks: ContentBlockParam[], cacheControl: AnthropicCacheControl): boolean {\n\tfor (let index = blocks.length - 1; index >= 0; index--) {\n\t\tconst block = blocks[index];\n\t\t// Anthropic rejects cache_control on generated reasoning and fallback\n\t\t// boundary blocks. Preserve the requested trailing boundary on every\n\t\t// ordinary content block, including tool use and tool results.\n\t\tif (block.type === \"thinking\" || block.type === \"redacted_thinking\" || block.type === \"fallback\") {\n\t\t\tcontinue;\n\t\t}\n\t\tif (\"cache_control\" in block && block.cache_control != null) return false;\n\t\tblocks[index] = { ...block, cache_control: cloneAnthropicCacheControl(cacheControl) };\n\t\treturn true;","sourceCodeStart":3156,"sourceCodeEnd":3192,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/anthropic.ts#L3156-L3192","documentation":"AIError.ConfigurationError thrown by ensureMaxTokensForThinking in the Anthropic provider. Anthropic requires thinking budget_tokens to be strictly less than max_tokens; the library reserves OUTPUT_FALLBACK_BUFFER (4000) tokens for non-thinking output, so it raises max_tokens to budgetTokens + 4000 first. If even the raised max_tokens (after any provider/user cap) cannot exceed the buffer — i.e. clamped = raisedMaxTokens - 4000 <= 0 — no valid thinking budget exists and the request is rejected before hitting the API.","triggerScenarios":"Sending a request with extended thinking enabled whose budget_tokens is <= OUTPUT_FALLBACK_BUFFER (4000) while the effective max_tokens after raising is <= 4000 — practically a thinking budget at or below 4000 tokens combined with a max_tokens cap that keeps raisedMaxTokens <= 4000, in ensureMaxTokensForThinking (packages/ai/src/providers/anthropic.ts:3165).","commonSituations":"Configuring thinking budget_tokens of 1024/2048 (small values copied from examples) with a low max_tokens; a model or deployment policy caps max_tokens at/below 4000; a model cap or KDL limits rule forces raisedMaxTokens below the buffer so clampedBudget <= 0.","solutions":["Raise max_tokens so it exceeds OUTPUT_FALLBACK_BUFFER (4000) — e.g. max_tokens >= budget_tokens + 4000","Raise thinking.budget_tokens above 4000 (Anthropic's practical minimum is 1024, but this library needs budget + 4000 headroom within max_tokens)","Check the model's max output limit; if the model caps max_tokens at <= 4000, use a model with a higher output limit or disable extended thinking","Remove any explicit max_tokens cap in your request/options that forces raisedMaxTokens <= 4000"],"exampleFix":"// before\nconst params = { max_tokens: 3000, thinking: { type: \"enabled\", budget_tokens: 2000 } };\n// after: leave headroom for output (budget + 4000 buffer)\nconst params = { max_tokens: 6000, thinking: { type: \"enabled\", budget_tokens: 2000 } };","handlingStrategy":"validation","validationCode":"function assertThinkingFits(maxTokens: number, budgetTokens: number): void {\n  const OUTPUT_FALLBACK_BUFFER = 4000;\n  if (budgetTokens + OUTPUT_FALLBACK_BUFFER > maxTokens) {\n    throw new Error(\n      `max_tokens must exceed budget_tokens + ${OUTPUT_FALLBACK_BUFFER}; got max_tokens=${maxTokens}, budget=${budgetTokens}`,\n    );\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const result = await session.prompt(model, paramsWithThinking);\n} catch (err) {\n  if (err instanceof AIError.ConfigurationError && err.message.includes(\"thinking budget\")) {\n    // fix config: raise max_tokens or lower/raise budget_tokens, then retry once\n  }\n  throw err;\n}","preventionTips":["When enabling extended thinking, always set max_tokens >= budget_tokens + 4000","Never set thinking budget_tokens at or below 4000 with a low max_tokens cap","Check the model's max output limit before choosing thinking budgets (avoid models capped at <= 4000 output tokens for thinking workloads)","Centralize thinking/max_tokens sizing in one helper instead of scattering literals"],"tags":["anthropic","configuration","thinking","max-tokens","validation"],"backgroundTag":"thinking-budget-exceeds-max-tokens","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}