{"record":{"id":"780fa681ba6dadf9","repo":"sgl-project/sglang","slug":"invalid-messages-at-index-assistant-msg","errorCode":null,"errorMessage":"Invalid messages at {index}:\n{assistant_msg}","messagePattern":"Invalid messages at (.+?):\n(.+?)","errorType":"exception","errorClass":"DS32EncodingError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/entrypoints/openai/encoding_dsv32.py","lineNumber":235,"sourceCode":"        prompt += user_msg_template.format(content=content)\n\n        if index == last_user_idx and thinking_mode == \"thinking\":\n            prompt += thinking_start_token\n        else:\n            prompt += thinking_end_token\n\n    elif role == \"tool\":\n        prev_assistant_idx = index - 1\n        assistant_msg = messages[prev_assistant_idx]\n        while prev_assistant_idx >= 0 and assistant_msg.get(\"role\") == \"tool\":\n            prev_assistant_idx -= 1\n            assistant_msg = messages[prev_assistant_idx]\n\n        if not (\n            index == 0\n            or (prev_assistant_idx >= 0 and assistant_msg.get(\"role\") == \"assistant\")\n        ):\n            raise DS32EncodingError(f\"Invalid messages at {index}:\\n{assistant_msg}\")\n\n        tool_call_order = index - prev_assistant_idx\n        assistant_tool_calls = assistant_msg.get(\"tool_calls\")\n        if not (assistant_tool_calls and len(assistant_tool_calls) >= tool_call_order):\n            raise DS32EncodingError(\"No tool calls but found tool output\")\n\n        if tool_call_order == 1:\n            prompt += \"\\n\\n<function_results>\"\n\n        prompt += tool_output_template.format(content=content)\n\n        if tool_call_order == len(assistant_tool_calls):\n            prompt += \"\\n</function_results>\"\n\n            if index >= last_user_idx and thinking_mode == \"thinking\":\n                prompt += \"\\n\\n\" + thinking_start_token\n            else:\n                prompt += \"\\n\\n\" + thinking_end_token","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/entrypoints/openai/encoding_dsv32.py#L217-L253","documentation":"DSv32 tool-message validation failed: a tool-role message appears where the preceding assistant turn is invalid. The encoder requires each tool message to immediately follow an assistant message (or be at index 0 with a prior assistant found), otherwise it raises DS32EncodingError showing the offending assistant message.","triggerScenarios":"A 'tool' role message that follows a user/system message instead of an assistant message, or two consecutive tool outputs not traceable to a preceding assistant turn with tool_calls.","commonSituations":"Client-side truncation that drops the assistant tool_call turn; history replay that reorders messages; manually constructed conversation logs missing the assistant step.","solutions":["Ensure every tool message directly follows the assistant message whose tool_calls produced it.","Restore the missing assistant tool_call turn in the history.","Rebuild the transcript so assistant(tool_calls) -> tool pairs stay adjacent."],"exampleFix":"# before\n[{\"role\":\"user\",\"content\":\"...\"},{\"role\":\"tool\",\"content\":\"42\"}]\n# after\n[{\"role\":\"user\",\"content\":\"...\"},{\"role\":\"assistant\",\"tool_calls\":[...]},{\"role\":\"tool\",\"content\":\"42\"}]","handlingStrategy":"validation","validationCode":"prev=None\nfor m in messages:\n    if m['role']=='tool' and (prev is None or prev['role']!='assistant'):\n        raise ValueError('tool message must follow assistant')\n    prev=m","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep assistant(tool_calls)->tool pairs adjacent.","Validate transcript ordering before each request."],"tags":["deepseek","tool-calls","conversation-history"],"backgroundTag":"tool-call-sequence-invalid","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}