browser-use/browser-use · error · ValueError

Must provide either browser_session or both dom_service and

Error message

Must provide either browser_session or both dom_service and target_id

What it means

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.

Source

Thrown at browser_use/dom/markdown_extractor.py:63

	Raises:
	    ValueError: If neither browser_session nor (dom_service + target_id) are provided
	"""
	# Validate input parameters
	if browser_session is not None:
		if dom_service is not None or target_id is not None:
			raise ValueError('Cannot specify both browser_session and dom_service/target_id')
		# Browser session path (tools service)
		enhanced_dom_tree = await _get_enhanced_dom_tree_from_browser_session(browser_session)
		current_url = await browser_session.get_current_page_url()
		method = 'enhanced_dom_tree'
	elif dom_service is not None and target_id is not None:
		# DOM service path (page actor)
		# Lazy fetch all_frames inside get_dom_tree if needed (for cross-origin iframes)
		enhanced_dom_tree, _ = await dom_service.get_dom_tree(target_id=target_id, all_frames=None)
		current_url = None  # Not available via DOM service
		method = 'dom_service'
	else:
		raise ValueError('Must provide either browser_session or both dom_service and target_id')

	# Use the HTML serializer with the enhanced DOM tree
	html_serializer = HTMLSerializer(extract_links=extract_links)
	page_html = html_serializer.serialize(enhanced_dom_tree)

	original_html_length = len(page_html)

	content, initial_markdown_length, chars_filtered = convert_html_to_markdown(page_html, extract_images=extract_images)

	final_filtered_length = len(content)

	# Content statistics
	stats = {
		'method': method,
		'original_html_chars': original_html_length,
		'initial_markdown_chars': initial_markdown_length,
		'filtered_chars_removed': chars_filtered,
		'final_filtered_chars': final_filtered_length,

View on GitHub (pinned to 6c73fced2f)

Solutions

  1. If you have a browser session, pass browser_session
  2. If you use the DOM-service path, always pass dom_service AND target_id together
  3. Guard upstream: skip the call when target_id is None instead of forwarding it

Example fix

# before
md = await markdown_extractor.extract_markdown(dom_service=svc, target_id=None)

# after
if tid is None:
    return
md = await markdown_extractor.extract_markdown(dom_service=svc, target_id=tid)
Defensive patterns

Strategy: validation

Validate before calling

if browser_session is None and (dom_service is None or target_id is None):
    raise ValueError('provide browser_session, or both dom_service and target_id, before calling')

Type guard

def extractor_args_valid(browser_session=None, dom_service=None, target_id=None) -> bool:
    if browser_session is not None:
        return dom_service is None and target_id is None
    return dom_service is not None and target_id is not None

Try / catch

try:
    md = await markdown_extractor.extract_markdown(dom_service=svc, target_id=tid)
except ValueError as e:
    if 'Must provide' in str(e):
        tid = await resolve_target_id()  # backfill the missing piece and retry
        md = await markdown_extractor.extract_markdown(dom_service=svc, target_id=tid)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of browser-use/browser-use@6c73fced2f (2026-08-14). Data as JSON: /api/errors/d4f2d2a36820b52b. Report an issue: GitHub.