{"record":{"id":"d4f2d2a36820b52b","repo":"browser-use/browser-use","slug":"must-provide-either-browser-session-or-both-dom-se","errorCode":null,"errorMessage":"Must provide either browser_session or both dom_service and target_id","messagePattern":"Must provide either browser_session or both dom_service and target_id","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"browser_use/dom/markdown_extractor.py","lineNumber":63,"sourceCode":"\tRaises:\n\t    ValueError: If neither browser_session nor (dom_service + target_id) are provided\n\t\"\"\"\n\t# Validate input parameters\n\tif browser_session is not None:\n\t\tif dom_service is not None or target_id is not None:\n\t\t\traise ValueError('Cannot specify both browser_session and dom_service/target_id')\n\t\t# Browser session path (tools service)\n\t\tenhanced_dom_tree = await _get_enhanced_dom_tree_from_browser_session(browser_session)\n\t\tcurrent_url = await browser_session.get_current_page_url()\n\t\tmethod = 'enhanced_dom_tree'\n\telif dom_service is not None and target_id is not None:\n\t\t# DOM service path (page actor)\n\t\t# Lazy fetch all_frames inside get_dom_tree if needed (for cross-origin iframes)\n\t\tenhanced_dom_tree, _ = await dom_service.get_dom_tree(target_id=target_id, all_frames=None)\n\t\tcurrent_url = None  # Not available via DOM service\n\t\tmethod = 'dom_service'\n\telse:\n\t\traise ValueError('Must provide either browser_session or both dom_service and target_id')\n\n\t# Use the HTML serializer with the enhanced DOM tree\n\thtml_serializer = HTMLSerializer(extract_links=extract_links)\n\tpage_html = html_serializer.serialize(enhanced_dom_tree)\n\n\toriginal_html_length = len(page_html)\n\n\tcontent, initial_markdown_length, chars_filtered = convert_html_to_markdown(page_html, extract_images=extract_images)\n\n\tfinal_filtered_length = len(content)\n\n\t# Content statistics\n\tstats = {\n\t\t'method': method,\n\t\t'original_html_chars': original_html_length,\n\t\t'initial_markdown_chars': initial_markdown_length,\n\t\t'filtered_chars_removed': chars_filtered,\n\t\t'final_filtered_chars': final_filtered_length,","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/browser-use/browser-use/blob/6c73fced2f6d45a11d88622fe56365a5fe18f28b/browser_use/dom/markdown_extractor.py#L45-L81","documentation":"The mirror-image validation of error 166: the extractor requires at least one complete input source — a browser_session, or both dom_service AND target_id. This fires when neither is given, or when only one of dom_service/target_id is supplied (a DOM service handle without a target id, or a target id without a service). The two arguments of the actor path are meaningless alone, so the call is rejected.","triggerScenarios":"Calling the extractor with no arguments; passing target_id but forgetting dom_service (or vice versa) after refactoring; passing None explicitly because upstream lookups returned None.","commonSituations":"Optional chaining where the caller does extract_markdown(dom_service=svc, target_id=maybe_none) and maybe_none is None on some pages; forgetting to await the session creation before calling.","solutions":["If you have a browser session, pass browser_session","If you use the DOM-service path, always pass dom_service AND target_id together","Guard upstream: skip the call when target_id is None instead of forwarding it"],"exampleFix":"# before\nmd = await markdown_extractor.extract_markdown(dom_service=svc, target_id=None)\n\n# after\nif tid is None:\n    return\nmd = await markdown_extractor.extract_markdown(dom_service=svc, target_id=tid)","handlingStrategy":"validation","validationCode":"if browser_session is None and (dom_service is None or target_id is None):\n    raise ValueError('provide browser_session, or both dom_service and target_id, before calling')","typeGuard":"def extractor_args_valid(browser_session=None, dom_service=None, target_id=None) -> bool:\n    if browser_session is not None:\n        return dom_service is None and target_id is None\n    return dom_service is not None and target_id is not None","tryCatchPattern":"try:\n    md = await markdown_extractor.extract_markdown(dom_service=svc, target_id=tid)\nexcept ValueError as e:\n    if 'Must provide' in str(e):\n        tid = await resolve_target_id()  # backfill the missing piece and retry\n        md = await markdown_extractor.extract_markdown(dom_service=svc, target_id=tid)\n    else:\n        raise","preventionTips":["Never forward possibly-None target_id; skip or resolve it first","Assert argument completeness in wrapper functions before calling the extractor","Unit-test wrappers with None branches to catch partial-argument paths early"],"tags":["dom","markdown","validation","api-misuse"],"backgroundTag":null,"analyzedSha":"6c73fced2f6d45a11d88622fe56365a5fe18f28b","analyzedAt":"2026-08-14T19:42:40.557Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}