sgl-project/sglang · error · ValueError
Invalid number of contents in browser message
Error message
Invalid number of contents in browser message
What it means
For harmony messages addressed to a 'browser.*' recipient, parse_output_message expects exactly one content part (the JSON-encoded browser call). If message.content has any length other than 1, the structure is ambiguous and parsing aborts.
Source
Thrown at python/sglang/srt/entrypoints/harmony_utils.py:258
return get_encoding().stop_tokens_for_assistant_actions()
def get_streamable_parser_for_assistant() -> StreamableParser:
return StreamableParser(get_encoding(), role=Role.ASSISTANT)
def parse_output_message(message: Message):
if message.author.role != "assistant":
# This is a message from a tool to the assistant (e.g., search result).
# Don't include it in the final output for now. This aligns with
# OpenAI's behavior on models like o4-mini.
return []
output_items = []
recipient = message.recipient
if recipient is not None and recipient.startswith("browser."):
if len(message.content) != 1:
raise ValueError("Invalid number of contents in browser message")
content = message.content[0]
browser_call = orjson.loads(content.text)
# TODO: translate to url properly!
if recipient == "browser.search":
action = ActionSearch(
query=f"cursor:{browser_call.get('query', '')}", type="search"
)
elif recipient == "browser.open":
action = ActionOpenPage(
url=f"cursor:{browser_call.get('url', '')}", type="open_page"
)
elif recipient == "browser.find":
action = ActionFind(
pattern=browser_call["pattern"],
url=f"cursor:{browser_call.get('url', '')}",
type="find",
)
else:View on GitHub (pinned to 0132848349)
Solutions
- Ensure browser.* messages contain exactly one content part holding the full JSON payload
- If post-processing model output, merge split content parts into one before parsing
- Upgrade sglang if a newer version tolerates/normalizes multi-part browser messages
Example fix
# before msg = Message(..., recipient="browser.search", content=[p1, p2]) # after msg = Message(..., recipient="browser.search", content=[merged_single_part])
Defensive patterns
Strategy: validation
Validate before calling
if message.recipient and message.recipient.startswith("browser."):
assert len(message.content) == 1, "browser messages need exactly one content part" Type guard
def is_wellformed_browser_message(message) -> bool:
return (
message.recipient is not None
and message.recipient.startswith("browser.")
and len(message.content) == 1
) Try / catch
try:
items = parse_output_message(message)
except ValueError as e:
if "Invalid number of contents" in str(e):
return [] # drop malformed browser message
raise Prevention
- When building browser messages, always attach a single JSON content part
- Validate model output structure before parsing in post-processing pipelines
When it happens
Trigger: A model-produced or hand-crafted message with recipient like 'browser.search' whose content list is empty or has 2+ parts.
Common situations: Malformed model output splitting the browser-call JSON across multiple content blocks; clients assembling harmony messages manually and appending extra text parts.
Related errors
- No call message found for {call_id}
- Unknown browser action: {recipient}
- 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/5e3ad2feed6814f1.
Report an issue: GitHub.