{"record":{"id":"7c50279d809e6721","repo":"sgl-project/sglang","slug":"no-tool-call-found","errorCode":null,"errorMessage":"No tool call found","messagePattern":"No tool call found","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/entrypoints/context.py","lineNumber":142,"sourceCode":"        return recipient is not None and (\n            recipient.startswith(\"browser.\") or recipient.startswith(\"python\")\n        )\n\n    async def call_tool(self) -> list[Message]:\n        if not self.messages:\n            return []\n        last_msg = self.messages[-1]\n        recipient = last_msg.recipient\n        if recipient is not None:\n            if recipient.startswith(\"browser.\"):\n                return await self.call_search_tool(\n                    self.tool_sessions[\"browser\"], last_msg\n                )\n            elif recipient.startswith(\"python\"):\n                return await self.call_python_tool(\n                    self.tool_sessions[\"python\"], last_msg\n                )\n        raise ValueError(\"No tool call found\")\n\n    def render_for_completion(self) -> list[int]:\n        return render_for_completion(self.messages)\n\n    async def call_search_tool(\n        self, tool_session: Union[\"ClientSession\", Tool], last_msg: Message\n    ) -> list[Message]:\n        if isinstance(tool_session, Tool):\n            return await tool_session.get_result(self)\n        tool_name = last_msg.recipient.split(\".\")[1]\n        args = orjson.loads(last_msg.content[0].text)\n        result = await tool_session.call_tool(tool_name, args)\n        result_str = result.content[0].text\n        content = TextContent(text=result_str)\n        author = Author(role=Role.TOOL, name=last_msg.recipient)\n        return [Message(author=author, content=[content], recipient=Role.ASSISTANT)]\n\n    async def call_python_tool(","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/entrypoints/context.py#L124-L160","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","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"],"exampleFix":"# before\nresult = await context.call_tool(last_msg)\n# after\nif any(getattr(b, \"type\", None) == \"tool_use\" for b in last_msg.content):\n    result = await context.call_tool(last_msg)\nelse:\n    result = None  # model produced a final answer","handlingStrategy":"type-guard","validationCode":"has_tool = any(getattr(b, \"type\", None) == \"tool_use\" for b in last_msg.content)\nif has_tool:\n    result = await context.call_tool(last_msg)","typeGuard":"def message_has_tool_call(msg) -> bool:\n    return any(getattr(b, \"type\", None) == \"tool_use\" for b in getattr(msg, \"content\", []))","tryCatchPattern":"try:\n    result = await context.call_tool(last_msg)\nexcept ValueError as e:\n    if 'No tool call found' in str(e):\n        result = None  # treat as final answer\n    else:\n        raise","preventionTips":["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"],"tags":["agent","tool-call","dispatch","no-op"],"backgroundTag":"missing-tool-call","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}