{"record":{"id":"6dad1ba6215be887","repo":"sgl-project/sglang","slug":"thinking-budget-tokens-is-not-allowed-when-thinkin","errorCode":null,"errorMessage":"thinking.budget_tokens is not allowed when thinking.type is 'disabled'","messagePattern":"thinking\\.budget_tokens is not allowed when thinking\\.type is 'disabled'","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"python/sglang/srt/entrypoints/anthropic/protocol.py","lineNumber":297,"sourceCode":"    display: Optional[Literal[\"summarized\", \"omitted\"]] = None\n\n    @model_validator(mode=\"after\")\n    def _validate_thinking_shape(self):\n        # Cross-field rules mirror the SDK's three discriminated variants.\n        if self.type == \"enabled\":\n            if self.budget_tokens is None:\n                raise ValueError(\n                    \"thinking.budget_tokens is required when \"\n                    \"thinking.type is 'enabled'\"\n                )\n            if self.budget_tokens < 1024:\n                raise ValueError(\n                    \"thinking.budget_tokens must be >= 1024 \"\n                    \"(got {})\".format(self.budget_tokens)\n                )\n        elif self.type == \"disabled\":\n            if self.budget_tokens is not None:\n                raise ValueError(\n                    \"thinking.budget_tokens is not allowed when \"\n                    \"thinking.type is 'disabled'\"\n                )\n            if self.display is not None:\n                raise ValueError(\n                    \"thinking.display is not allowed when \"\n                    \"thinking.type is 'disabled'\"\n                )\n        elif self.type == \"adaptive\":\n            if self.budget_tokens is not None:\n                raise ValueError(\n                    \"thinking.budget_tokens is not allowed when \"\n                    \"thinking.type is 'adaptive'\"\n                )\n        return self\n\n\nclass AnthropicTaskBudget(BaseModel):","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/entrypoints/anthropic/protocol.py#L279-L315","documentation":"Raised by the Anthropic-compatible endpoint's validator when a request sets thinking.type='disabled' but also supplies a budget_tokens value. Per the Anthropic contract, budget_tokens is only meaningful when thinking is enabled, so providing it alongside 'disabled' is rejected as a 400 before inference.","triggerScenarios":"POST /v1/messages with {\"thinking\": {\"type\": \"disabled\", \"budget_tokens\": 1024}}. Any non-null budget_tokens together with type='disabled' triggers it.","commonSituations":"Toggling a previously-enabled thinking config to 'disabled' while leaving the budget field in place; building requests from a shared config object; SDK wrappers that always serialize budget_tokens even when unset becomes a number.","solutions":["Remove budget_tokens when thinking.type is 'disabled'","Or switch thinking.type to 'enabled' if you actually want thinking","Set budget_tokens to null/None instead of a number when disabling"],"exampleFix":"// before\n{\"thinking\": {\"type\": \"disabled\", \"budget_tokens\": 2048}}\n// after\n{\"thinking\": {\"type\": \"disabled\"}}","handlingStrategy":"validation","validationCode":"if thinking[\"type\"] == \"disabled\":\n    thinking.pop(\"budget_tokens\", None)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build thinking dict per type, never mutate a shared template","Omit keys rather than sending null"],"tags":["anthropic","thinking","validation","request-validation","pydantic"],"backgroundTag":"request-validation-failed","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}