sgl-project/sglang · error · NotImplementedError
deepseek_v4 merges tool messages into user; please preproces
Error message
deepseek_v4 merges tool messages into user; please preprocess with merge_tool_messages()
What it means
deepseek_v4's template merges tool outputs into the following user message; raw 'tool' role messages are not rendered and raise NotImplementedError, telling you to preprocess with merge_tool_messages().
Source
Thrown at python/sglang/srt/entrypoints/openai/encoding_dsv4.py:388
if b.get("type") == "text":
text_parts.append(b.get("text", ""))
else:
text_parts.append(f"[Unsupported {b.get('type')}]")
tool_content = "\n\n".join(text_parts)
parts.append(tool_output_template.format(content=tool_content))
else:
parts.append(f"[Unsupported {block_type}]")
prompt += "\n\n".join(parts)
else:
prompt += content or ""
elif role == "latest_reminder":
prompt += LATEST_REMINDER_SP_TOKEN + latest_reminder_msg_template.format(
content=content
)
elif role == "tool":
raise NotImplementedError(
"deepseek_v4 merges tool messages into user; please preprocess with merge_tool_messages()"
)
elif role == "assistant":
thinking_part = ""
tc_content = ""
if tool_calls:
tc_list = [
tool_call_template.format(
dsml_token=dsml_token,
name=tc.get("name"),
arguments=encode_arguments_to_dsml(tc),
)
for tc in tool_calls
]
tc_content += "\n\n" + tool_calls_template.format(
dsml_token=dsml_token,View on GitHub (pinned to 0132848349)
Solutions
- Call merge_tool_messages(messages) before encoding/sending.
- Or configure the serving adapter to apply the merge automatically.
- Replace tool messages with merged user messages containing <function_results> blocks if merging manually.
Example fix
# before
messages = [{...assistant w/ tool_calls...},{"role":"tool","content":"42"}]
# after
from sglang.srt.entrypoints.openai.encoding_dsv4 import merge_tool_messages
messages = merge_tool_messages(messages) Defensive patterns
Strategy: fallback
Validate before calling
from sglang.srt.entrypoints.openai.encoding_dsv4 import merge_tool_messages messages=[m for m in messages if m['role']!='tool'] or merge_tool_messages(messages)
Type guard
def has_raw_tool_role(msgs): return any(m['role']=='tool' for m in msgs)
Prevention
- Run merge_tool_messages() on every OpenAI-style transcript before DSv4 encoding.
When it happens
Trigger: Sending a messages array containing role='tool' directly to the DSv4 encoder/serving endpoint without calling merge_tool_messages() first.
Common situations: Replaying OpenAI-style tool transcripts verbatim; client frameworks that always emit tool-role messages; missing preprocessing step in a custom integration.
Related errors
- DSV4 draft state transfer expects SWA-only NextN layers
- DSV4 target and draft pools must use the same unified-KV mod
- DSV4 target and draft pools must share SWA ring geometry: ta
- DSV4 target and draft pools must share the SWA index mapping
- DSV4 target and draft pools must share paged SWA geometry: t
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/ef44c6c7ae4220dd.
Report an issue: GitHub.