fix: close_tab() recovers session state when closing the currently attached tab - #393
fix: close_tab() recovers session state when closing the currently attached tab#393mvanhorn wants to merge 2 commits into
Conversation
…tached tab Implements the work described in 2026-05-26-115-fix-close-tab-dangling-session-state-plan.md. Closes browser-use#379.
There was a problem hiding this comment.
1 issue found across 2 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
Track the fallback about:blank tab created in single-tab mode and close it best-effort when Target.closeTarget fails, so the failure path doesn't leak an extra tab. Also treat success:false responses from Target.closeTarget as failures.
|
Good catch by cubic, the leak was real. Fixed in f33ea09: the single-tab fallback tab id is tracked and best-effort closed when |
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/browser_harness/helpers.py">
<violation number="1" location="src/browser_harness/helpers.py:364">
P2: The rollback path in `close_tab()` uses a bare `raise` in the `except` handler, which makes it fragile if `switch_tab(cur)` raises a second exception. If `_close_target` fails because the tab is already gone, `switch_tab(cur)` will raise its own error, mask the original close error, and skip the fallback cleanup entirely. Consider capturing the original exception and making the rollback best-effort so both the original error and cleanup run reliably.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| _close_target(target_id) | ||
| except Exception: | ||
| switch_tab(cur) | ||
| if fallback_id is not None: |
There was a problem hiding this comment.
P2: The rollback path in close_tab() uses a bare raise in the except handler, which makes it fragile if switch_tab(cur) raises a second exception. If _close_target fails because the tab is already gone, switch_tab(cur) will raise its own error, mask the original close error, and skip the fallback cleanup entirely. Consider capturing the original exception and making the rollback best-effort so both the original error and cleanup run reliably.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/browser_harness/helpers.py, line 364:
<comment>The rollback path in `close_tab()` uses a bare `raise` in the `except` handler, which makes it fragile if `switch_tab(cur)` raises a second exception. If `_close_target` fails because the tab is already gone, `switch_tab(cur)` will raise its own error, mask the original close error, and skip the fallback cleanup entirely. Consider capturing the original exception and making the rollback best-effort so both the original error and cleanup run reliably.</comment>
<file context>
@@ -339,21 +345,27 @@ def close_tab(target=None):
+ _close_target(target_id)
except Exception:
switch_tab(cur)
+ if fallback_id is not None:
+ try:
+ _close_target(fallback_id)
</file context>
Summary
close_tab()now switches the harness to a surviving real tab (or a freshabout:blank) before closing the currently attached tab, so the daemon session never points at a dead target.Why this matters
Before this change, the no-arg form of
close_tab()issuedTarget.closeTargetagainst the attachedtargetIdwithout updating the daemon session thatswitch_tab()previously registered. Afterclose_tab()the daemon still believed the now-deadtargetId/sessionIdwas active, so the next call intojs(),page_info(),current_tab(), or_mark_tab()landed on a dead session and failed until the caller manuallyswitch_tab()'d.Repro:
Maintainer @sauravpanda filed #379 with a clear cause + Option (a) fix sketch.
Changes
close_tab(target=None)now detects whether the target equals the currently attached tab. If so, it picks a surviving real tab vialist_tabs(include_chrome=False)andswitch_tab()s to it before closing; if no other real tab exists, it opens a freshabout:blankfirst. The fast path for explicit non-current targets is unchanged.Target.closeTargetfails after the switch, the original session is restored rather than left half-migrated.Testing
pytest tests/unit/test_helpers.py— 22/22 pass. Added 4 new test cases:page_info()succeeds.Fixes #379
Summary by cubic
Fixes a bug where closing the currently attached tab left the session pointing at a dead target. Now close_tab() switches to a live tab (or creates about:blank) before closing and cleans up on failure so follow-up calls work. Fixes #379.
Target.closeTargetresponses withsuccess: falseas failures.Written for commit f33ea09. Summary will update on new commits.