{"record":{"id":"6a0d8f80d55731b8","repo":"sgl-project/sglang","slug":"cannot-rewrap-thinking-history-no-reasoning-detec","errorCode":null,"errorMessage":"Cannot rewrap thinking history: no reasoning detector is configured for this model","messagePattern":"Cannot rewrap thinking history: no reasoning detector is configured for this model","errorType":"exception","errorClass":"ValueError","httpStatus":500,"severity":"error","filePath":"python/sglang/srt/entrypoints/openai/serving_chat.py","lineNumber":2330,"sourceCode":"    def supports_native_reasoning_history(self) -> bool:\n        \"\"\"Whether the chat encoder takes history as ``reasoning_content`` rather\n        than via :meth:`wrap_reasoning_history`; see\n        :func:`chat_encoding.spec_owns_reasoning_history` for why.\n        \"\"\"\n        return chat_encoding.spec_owns_reasoning_history(self.chat_encoding_spec)\n\n    def wrap_reasoning_history(self, reasoning_text: str) -> str:\n        \"\"\"Wrap prior-turn reasoning in the detector's own start/end tokens.\n\n        Pulling the delimiters from the detector keeps adapters in lockstep\n        with any future parser that ships non-``<think>`` markers — Mistral's\n        ``[THINK]``, Gemma4's ``think_start_self_label = \"thought\\\\n\"``, etc.\n        Falling back to a plain string is unsafe: it would let prior\n        thinking text reach a non-reasoning model as ordinary assistant\n        content, so the caller must surface this state, not paper over it.\n        \"\"\"\n        if self._reasoning_detector is None:\n            raise ValueError(\n                \"Cannot rewrap thinking history: no reasoning detector is \"\n                \"configured for this model\"\n            )\n        d = self._reasoning_detector\n        return (\n            f\"{d.think_start_token}{d.think_start_self_label}\"\n            f\"{reasoning_text}\\n{d.think_end_token}\"\n        )\n\n    def _reasoning_default_mode(self) -> Optional[str]:\n        if self._reasoning_detector is None:\n            return None\n        return self._reasoning_detector.reasoning_default\n\n    def _get_reasoning_toggle_param(self) -> Optional[str]:\n        \"\"\"Resolve the chat-template kwarg that toggles reasoning, if any.\"\"\"\n        config = self.template_manager.reasoning_config\n        if config is not None:","sourceCodeStart":2312,"sourceCodeEnd":2348,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/entrypoints/openai/serving_chat.py#L2312-L2348","documentation":"A chat request contains assistant reasoning/thinking blocks in history, and the server needs to re-wrap them with the model's think tokens (e.g. <think>), but no reasoning parser is configured for the served model. Since silently flattening thinking text into ordinary content would leak reasoning into a non-reasoning model, the server raises instead.","triggerScenarios":"Calling /v1/chat/completions (or Anthropic-style API) with prior assistant messages containing reasoning_content blocks while the server was launched without --reasoning-parser (so self._reasoning_detector is None).","commonSituations":"Replaying a captured conversation (from a reasoning model) against a non-reasoning model; forgetting to set --reasoning-parser deepseek-r1/qwen3 etc.; migrating clients that persist reasoning_content in history.","solutions":["Launch the server with --reasoning-parser matching the model (e.g. deepseek-r1, qwen3) so a detector exists","Strip reasoning_content / thinking blocks from assistant history before sending to a non-reasoning model","If the target model is a reasoner, verify the correct parser name (see sglang ReasoningParser registry)"],"exampleFix":"# before\nmessages=[{\"role\":\"assistant\",\"content\":\"ans\",\"reasoning_content\":\"chain...\"}]  # to non-reasoning model\n# after\nmessages=[{\"role\":\"assistant\",\"content\":\"ans\"}]","handlingStrategy":"validation","validationCode":"def clean_history(messages):\n    return [{k: v for k, v in m.items() if k != 'reasoning_content'} for m in messages]","typeGuard":"def has_reasoning_history(messages) -> bool:\n    return any(m.get('reasoning_content') or m.get('thinking_blocks') for m in messages if m.get('role') == 'assistant')","tryCatchPattern":null,"preventionTips":["Strip reasoning_content from history when targeting non-reasoning models","Launch with --reasoning-parser when serving reasoning models","Detect model capability before replaying captured transcripts"],"tags":["reasoning","chat-history","server-config"],"backgroundTag":"reasoning-parser-misconfigured","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}