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

  1. Check last_msg.recipient starts with 'browser.' before calling get_result
  2. Verify the model prompt/harmony encoding includes the recipient field for tool calls
  3. 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

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


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/555d1e8d4ede0791. Report an issue: GitHub.