{"record":{"id":"718dac5f44bbb736","repo":"sgl-project/sglang","slug":"unknown-browser-cursor-cursor","errorCode":null,"errorMessage":"Unknown browser cursor: {cursor}","messagePattern":"Unknown browser cursor: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/entrypoints/tool.py","lineNumber":200,"sourceCode":"            return self._format_matches(pattern, text)\n\n        searchable_text = \"\\n\\n\".join(\n            self._best_snippet(page) for page in state[\"pages\"].values()\n        )\n        return self._format_matches(pattern, searchable_text)\n\n    def _resolve_url(self, context: \"ConversationContext\", args: dict[str, Any]) -> str:\n        if args.get(\"url\"):\n            return str(args[\"url\"])\n\n        state = self._browser_state(context)\n        cursor = self._normalize_cursor(args.get(\"cursor\"))\n        if not cursor:\n            raise ValueError(\"browser.open requires a cursor or url\")\n\n        page = state[\"pages\"].get(cursor)\n        if page is None:\n            raise ValueError(f\"Unknown browser cursor: {cursor}\")\n\n        url = page.get(\"url\") or page.get(\"id\")\n        if not url:\n            raise ValueError(f\"No URL recorded for browser cursor: {cursor}\")\n        return str(url)\n\n    def _normalize_cursor(self, cursor: Any) -> str | None:\n        if cursor is None:\n            return None\n        cursor_str = str(cursor)\n        # GPT-OSS emits 0 as a 1-based cursor; map it to the first result.\n        if cursor_str == \"0\":\n            return \"1\"\n        return cursor_str\n\n    def _cursor_for_url(self, state: dict[str, Any], url: str) -> str | None:\n        for cursor, page in state[\"pages\"].items():\n            if page.get(\"url\") == url or page.get(\"id\") == url:","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/entrypoints/tool.py#L182-L218","documentation":"SGLang's browser resolver was given a cursor (e.g. a search-result index like '0' or '1-3'), but the per-context browser state dict has no page entry for it. Cursors only exist after a search/open result recorded them on the conversation context.","triggerScenarios":"browser.open or browser.find with {\"cursor\": \"5\"} when only cursors 0-2 were recorded in context._sglang_exa_browser_state['pages'], or a cursor from a different/earlier conversation context.","commonSituations":"Model hallucinating a cursor beyond the result list, reusing a cursor after context state was reset, or a new context object lacking prior state (e.g. multi-turn session where _sglang_exa_browser_state was not persisted).","solutions":["Re-run browser.search to (re)populate cursors before referencing them","Use a cursor that actually appears in the last formatted search results","Persist/reattach the browser state on the context across turns if needed"],"exampleFix":"# before\nargs = {\"cursor\": \"7\"}  # only 3 results existed\n# after\nargs = {\"cursor\": \"2\"}","handlingStrategy":"validation","validationCode":"state = getattr(context, \"_sglang_exa_browser_state\", {\"pages\": {}})\ncursor = str(args[\"cursor\"])\nassert cursor in state[\"pages\"], f\"unknown cursor {cursor}\"","typeGuard":"def cursor_exists(context, cursor: str) -> bool:\n    pages = getattr(context, \"_sglang_exa_browser_state\", {}).get(\"pages\", {})\n    return str(cursor) in pages","tryCatchPattern":"try:\n    url = tool._resolve_url(context, args)\nexcept ValueError as e:\n    if \"Unknown browser cursor\" in str(e):\n        await tool._dispatch_browser_call(context, \"browser.search\", {\"query\": ...})\n        url = tool._resolve_url(context, args)","preventionTips":["Restrict cursors to those present in the last search result formatting","Carry browser state on the same context object across turns"],"tags":["browser","cursor","state","tool-calling"],"backgroundTag":"invalid-cursor-reference","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}