sgl-project/sglang · error · ValueError
No browser tool call found
Error message
No browser tool call found
What it means
Thrown by SGLang's browser Tool.get_result when the last message in the conversation has no recipient (tool-call target) or its recipient does not start with 'browser.'. The tool flow expects the model to emit a browser.* tool call as the final message before harvesting a result.
Source
Thrown at python/sglang/srt/entrypoints/tool.py:53
print_info_once("Browser tool initialized")
return
api_key = envs.EXA_API_KEY.get()
if not api_key:
self.enabled = False
print_warning_once("EXA_API_KEY is not set, browsing is disabled")
return
self.exa_client = ExaClient(api_key, config=ExaSearchConfig.from_env())
print_info_once("Browser tool initialized")
async def get_result(self, context: "ConversationContext") -> Any:
from openai_harmony import Author, Message, Role, TextContent
last_msg = context.messages[-1]
recipient = last_msg.recipient
if recipient is None or not recipient.startswith("browser."):
raise ValueError("No browser tool call found")
try:
args = orjson.loads(last_msg.content[0].text)
result_text = await self._dispatch_browser_call(context, recipient, args)
except Exception as exc:
logger.exception("Browser tool call failed")
result_text = f"Browser tool call failed: {exc}"
content = TextContent(text=result_text)
author = Author(role=Role.TOOL, name=recipient)
return [Message(author=author, content=[content], recipient=Role.ASSISTANT)]
async def _dispatch_browser_call(
self, context: "ConversationContext", recipient: str, args: dict[str, Any]
) -> str:
if recipient == "browser.search":
query = args.get("query")
if not query:View on GitHub (pinned to 0132848349)
Solutions
- Check last_msg.recipient starts with 'browser.' before calling get_result
- Verify the model prompt/harmony encoding includes the recipient field for tool calls
- Route non-browser recipients to their matching tool implementation
Example fix
# before
result = await tool.get_result(context)
# after
last = context.messages[-1]
if last.recipient and last.recipient.startswith("browser."):
result = await tool.get_result(context)
else:
raise ValueError("No browser tool call found") Defensive patterns
Strategy: type-guard
Validate before calling
last = context.messages[-1]
recipient = getattr(last, "recipient", None)
assert recipient and recipient.startswith("browser."), "expected a browser.* tool call" Type guard
def is_browser_call(msg) -> bool:
r = getattr(msg, "recipient", None)
return r is not None and r.startswith("browser.") Try / catch
try:
result = await tool.get_result(context)
except ValueError as e:
if "No browser tool call" in str(e):
# route to the correct tool or re-prompt
... Prevention
- Only call get_result after confirming the last message targets browser.*
- Route by recipient prefix before dispatching to a tool implementation
When it happens
Trigger: Calling get_result(context) when context.messages[-1].recipient is None, or when the model emitted a non-browser recipient such as 'python.execute' or a plain assistant reply with no tool call.
Common situations: Routing a non-browser tool conversation into BrowserTool.get_result, a model that failed to emit a recipient header, or invoking get_result at the wrong point in the tool loop (before the model's tool-call turn arrives).
Related errors
- Function tools must include a name.
- Assistant tool call function.arguments must be a JSON object
- v_cache must be provided
- q can only be None when only_qv=True
- q must be provided unless qv is provided with only_qv=True
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/555d1e8d4ede0791.
Report an issue: GitHub.