browser-use/browser-use · error · ValueError

success=True can only be set when is_done=True. For regular

Error message

success=True can only be set when is_done=True. For regular actions that succeed, leave success as None. Use success=False only for actions that fail.

What it means

`ActionResult` uses a three-valued `success` field: None (default, ordinary successful action), False (action failed), and True — which is reserved exclusively for terminal results where `is_done=True`. A Pydantic model validator rejects `success=True` on any non-done action, because success-flags on intermediate actions would corrupt the agent's evaluation of whether the overall task succeeded.

Source

Thrown at browser_use/agent/views.py:344

	# Always include in long term memory
	long_term_memory: str | None = None  # Memory of this action

	# if update_only_read_state is True we add the extracted_content to the agent context only once for the next step
	# if update_only_read_state is False we add the extracted_content to the agent long term memory if no long_term_memory is provided
	extracted_content: str | None = None
	include_extracted_content_only_once: bool = False  # Whether the extracted content should be used to update the read_state

	# Metadata for observability (e.g., click coordinates)
	metadata: dict | None = None

	# Deprecated
	include_in_memory: bool = False  # whether to include in extracted_content inside long_term_memory

	@model_validator(mode='after')
	def validate_success_requires_done(self):
		"""Ensure success=True can only be set when is_done=True"""
		if self.success is True and self.is_done is not True:
			raise ValueError(
				'success=True can only be set when is_done=True. '
				'For regular actions that succeed, leave success as None. '
				'Use success=False only for actions that fail.'
			)
		return self


class RerunSummaryAction(BaseModel):
	"""AI-generated summary for rerun completion"""

	summary: str = Field(description='Summary of what happened during the rerun')
	success: bool = Field(description='Whether the rerun completed successfully based on visual inspection')
	completion_status: Literal['complete', 'partial', 'failed'] = Field(
		description='Status of rerun completion: complete (all steps succeeded), partial (some steps succeeded), failed (task did not complete)'
	)


class StepMetadata(BaseModel):

View on GitHub (pinned to 6c73fced2f)

Solutions

  1. Drop `success=True` from intermediate results — return `ActionResult(extracted_content='...')` or `long_term_memory='...'`.
  2. Only set `success=True` together with `is_done=True` on the final result.
  3. Use `success=False` (with `error=`) exclusively for failed tool calls.

Example fix

# before
@tools.action('Fetch order status')
async def order_status(order_id: str) -> ActionResult:
    return ActionResult(success=True, extracted_content='shipped')

# after
@tools.action('Fetch order status')
async def order_status(order_id: str) -> ActionResult:
    return ActionResult(extracted_content='shipped')  # success stays None
Defensive patterns

Strategy: validation

Type guard

def valid_action_result(result) -> bool:
    return not (result.get('success') is True and result.get('is_done') is not True)

Prevention

When it happens

Trigger: A custom `@tools.action` returning `ActionResult(success=True)` without `is_done=True` — e.g. returning success=True on each completed sub-step, or copied from a done-style example.

Common situations: Writing custom tools that mimic older ActionResult semantics; porting code where success was a plain boolean; marking milestones with success=True instead of extracted_content/long_term_memory.

Related errors


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