browser-use/browser-use · error · ValueError

llm_screenshot_size dimensions must be at least 100 pixels

Error message

llm_screenshot_size dimensions must be at least 100 pixels

What it means

Agent.__init__ validation: both dimensions are ints but at least one is below 100 pixels. Screenshots smaller than 100px are useless for vision models, so the constructor enforces a floor. Both width AND height must be >= 100.

Source

Thrown at browser_use/agent/service.py:222

		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,
	):
		# Validate llm_screenshot_size
		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')
			self.logger.info(f'🖼️  LLM screenshot resizing enabled: {width}x{height}')
		if llm is None:
			default_llm_name = CONFIG.DEFAULT_LLM
			if default_llm_name:
				from browser_use.llm.models import get_llm_by_name

				llm = get_llm_by_name(default_llm_name)
			else:
				# No default LLM specified, use the original default
				from browser_use import ChatBrowserUse

				llm = ChatBrowserUse()

		# set flashmode = True if llm is ChatBrowserUse
		if llm.provider == 'browser-use':
			flash_mode = True

		# Flash mode strips plan fields from the output schema, so planning is structurally impossible

View on GitHub (pinned to 6c73fced2f)

Solutions

  1. Use at least 100x100; token savings are better achieved with vision_detail_level='low'
  2. If the intent was to disable resizing, pass llm_screenshot_size=None instead of tiny values
  3. Clamp computed sizes: size = (max(100, w), max(100, h))

Example fix

# before
agent = Agent(task=..., llm=llm, llm_screenshot_size=(64, 64))

# after
agent = Agent(task=..., llm=llm, llm_screenshot_size=None)  # disable resize
# or
agent = Agent(task=..., llm=llm, vision_detail_level='low')  # cheaper vision
Defensive patterns

Strategy: validation

Validate before calling

size = None if size is None else (max(100, int(size[0])), max(100, int(size[1])))

Type guard

def is_valid_screenshot_size(v) -> bool:
    return v is None or (isinstance(v, tuple) and len(v) == 2 and all(isinstance(x, int) and x >= 100 for x in v))

Try / catch

null

Prevention

When it happens

Trigger: Passing (64, 64) thumbnails; passing (0, 0) or negative values as 'disabled' sentinel; unit-test fixtures using tiny sizes; computed sizes that shrink with viewport math (e.g. width // 20).

Common situations: Trying to cut token cost with very small screenshots; test configs copied from unit tests; accidental transposition of coordinates or percentages (e.g. (10, 10) meaning 10%).

Related errors


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