sgl-project/sglang · error · ValueError
No tool call found
Error message
No tool call found
What it means
Raised by the agentic Context.call_tool dispatcher when the last assistant message contains no parsable tool call, or the recipient string doesn't match any known tool session prefix (browser/python/etc.). It is the fallthrough after all supported tool handlers have been tried, signaling the caller attempted to execute tools on a message that has none.
Source
Thrown at python/sglang/srt/entrypoints/context.py:142
return recipient is not None and (
recipient.startswith("browser.") or recipient.startswith("python")
)
async def call_tool(self) -> list[Message]:
if not self.messages:
return []
last_msg = self.messages[-1]
recipient = last_msg.recipient
if recipient is not None:
if recipient.startswith("browser."):
return await self.call_search_tool(
self.tool_sessions["browser"], last_msg
)
elif recipient.startswith("python"):
return await self.call_python_tool(
self.tool_sessions["python"], last_msg
)
raise ValueError("No tool call found")
def render_for_completion(self) -> list[int]:
return render_for_completion(self.messages)
async def call_search_tool(
self, tool_session: Union["ClientSession", Tool], last_msg: Message
) -> list[Message]:
if isinstance(tool_session, Tool):
return await tool_session.get_result(self)
tool_name = last_msg.recipient.split(".")[1]
args = orjson.loads(last_msg.content[0].text)
result = await tool_session.call_tool(tool_name, args)
result_str = result.content[0].text
content = TextContent(text=result_str)
author = Author(role=Role.TOOL, name=last_msg.recipient)
return [Message(author=author, content=[content], recipient=Role.ASSISTANT)]
async def call_python_tool(View on GitHub (pinned to 0132848349)
Solutions
- Check the last assistant message for tool_use blocks before calling call_tool; skip if it's plain text (the model finished)
- If truncation is the cause, raise max_tokens or adjust stop handling so tool calls aren't cut off
- Verify you pass the most recent assistant message and that the recipient prefix matches a registered tool session
Example fix
# before
result = await context.call_tool(last_msg)
# after
if any(getattr(b, "type", None) == "tool_use" for b in last_msg.content):
result = await context.call_tool(last_msg)
else:
result = None # model produced a final answer Defensive patterns
Strategy: type-guard
Validate before calling
has_tool = any(getattr(b, "type", None) == "tool_use" for b in last_msg.content)
if has_tool:
result = await context.call_tool(last_msg) Type guard
def message_has_tool_call(msg) -> bool:
return any(getattr(b, "type", None) == "tool_use" for b in getattr(msg, "content", [])) Try / catch
try:
result = await context.call_tool(last_msg)
except ValueError as e:
if 'No tool call found' in str(e):
result = None # treat as final answer
else:
raise Prevention
- Check for tool_use blocks before dispatching
- Guard agent loops with a has-tool-call condition
- Watch for truncated tool calls from low max_tokens
When it happens
Trigger: Calling context.call_tool(...) with an assistant Message whose content has no tool_use block, or after a model response that ended without invoking a tool (e.g. a final text answer).
Common situations: Agent loops that unconditionally call call_tool after every completion instead of checking whether the model requested a tool; stop_sequence or max_tokens truncation cutting off the tool call; parsing the wrong message (e.g. the user turn or an earlier assistant message).
Related errors
- Action endpoint is not implemented for {sampling_params_cls.
- Unknown disagg_role: {role}
- f"flash attention version {fa_ver} is not supported."
- Unsupported library: {transformers_or_diffusers}
- PD state transfer failed: unknown state_type={st}
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/7c50279d809e6721.
Report an issue: GitHub.