browser-use/browser-use · error · ValueError

llm_screenshot_size dimensions must be integers

Error message

llm_screenshot_size dimensions must be integers

What it means

Second-stage validation of `llm_screenshot_size`: after the value is confirmed to be a 2-tuple, both elements must be `int`. Floats (e.g. 1400.0), numeric strings, or None in either slot raise this ValueError. Note the check is strict `isinstance(x, int)` — booleans pass but are nonsensical sizes and will fail the 100px minimum anyway.

Source

Thrown at browser_use/beta/service.py:4310

		final_response_after_failure: bool = True,
		enable_planning: bool = True,
		planning_replan_on_stall: int = 3,
		planning_exploration_limit: int = 5,
		loop_detection_window: int = 20,
		loop_detection_enabled: bool = True,
		llm_screenshot_size: tuple[int, int] | None = None,
		message_compaction: MessageCompactionSettings | bool | None = True,
		max_clickable_elements_length: int = 40000,
		_url_shortening_limit: int = 25,
		enable_signal_handler: bool = True,
		**kwargs,
	):
		if llm_screenshot_size is not None:
			if not isinstance(llm_screenshot_size, tuple) or len(llm_screenshot_size) != 2:
				raise ValueError('llm_screenshot_size must be a tuple of (width, height)')
			width, height = llm_screenshot_size
			if not isinstance(width, int) or not isinstance(height, int):
				raise ValueError('llm_screenshot_size dimensions must be integers')
			if width < 100 or height < 100:
				raise ValueError('llm_screenshot_size dimensions must be at least 100 pixels')
		llm = _resolve_default_llm(llm)
		use_vision = True
		if browser and browser_session:
			raise ValueError('Cannot specify both "browser" and "browser_session" parameters. Use "browser" for the cleaner API.')
		if getattr(llm, 'provider', None) == 'browser-use':
			flash_mode = True
		if flash_mode:
			enable_planning = False
		if llm_screenshot_size is None:
			model_name = getattr(llm, 'model', '')
			# rsplit drops the provider prefix so gateway ids like 'anthropic/claude-sonnet-4-6'
			# get the same screenshot auto-config as direct Claude Sonnet models.
			if isinstance(model_name, str) and model_name.rsplit('/', 1)[-1].startswith('claude-sonnet'):
				llm_screenshot_size = (1400, 850)
		if page_extraction_llm is None:
			page_extraction_llm = llm

View on GitHub (pinned to 6c73fced2f)

Solutions

  1. Coerce explicitly: `llm_screenshot_size=(int(w), int(h))`.
  2. Round scaled values: `(round(w * scale), round(h * scale))`.
  3. Fix the config source to emit integers.

Example fix

# before
size = (base_w * 1.4, base_h * 1.4)  # floats
agent = BetaAgent(task=t, llm_screenshot_size=size)

# after
size = (round(base_w * 1.4), round(base_h * 1.4))
agent = BetaAgent(task=t, llm_screenshot_size=size)
Defensive patterns

Strategy: validation

Validate before calling

size = tuple(int(d) for d in cfg['llm_screenshot_size'])  # coerce before passing

Type guard

def is_int_pair(v) -> bool:
    return isinstance(v, tuple) and len(v) == 2 and all(isinstance(d, int) and not isinstance(d, bool) for d in v)

Prevention

When it happens

Trigger: Passing `(1400.0, 850.0)` from computed/float configs, `('1400', 850)` from unparsed strings, or dimensions derived from float math (e.g. `int * scale` without rounding).

Common situations: Scaling viewport dimensions by a DPI factor producing floats; values read from CSV/JSON as strings; config systems that type-coerce numbers to float.

Related errors


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