You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Now auto_attach always fires Target.setAutoAttach, which triggers Target.attachedToTarget CDP events for existing targets. These events call add_context, which captures the browser's implicit default context and promotes it to @default_context via @default_context ||= context. This implicit context is not usable for Target.createTarget.
reset conditionally clears @default_context. In v0.17.1, reset unconditionally set @default_context = nil. In v0.17.2, it only clears it if Target.getBrowserContexts lists it — but that API never returns implicit contexts. So after reset, @default_context still points to the stale implicit context.
The combination means:
First test fails — @default_context is the implicit context; create_target is rejected by Chrome.
All subsequent tests fail — reset never clears @default_context because the implicit context isn't in the getBrowserContexts list.
Why flatten: false matters
flatten: false is the documented workaround for using Ferrum/Cuprite with Browserless (see #540 comments). In v0.17.1, flatten: false also implicitly prevented auto_attach from running, which kept the implicit context out of Ferrum's state. The v0.17.2 removal of the guard broke this.
This preempts default_context's @default_context ||= create, so a proper explicit context is never created.
3. reset — conditional clear (secondary cause)
def reset
- @default_context = nil- @contexts.each_key { |id| dispose(id) }+ context_ids = @client.command("Target.getBrowserContexts")["browserContextIds"]+ @default_context = nil if context_ids.include?(@default_context&.id)+ @contexts.each_key { |id| dispose(id) if context_ids.include?(id) }
end
Target.getBrowserContexts only returns explicitly created contexts. The implicit context is never in the list, so @default_context is never cleared between tests.
To reproduce
1. Start Browserless
docker run --rm -p 3311:3311 -e PORT=3311 -e CONNECTION_TIMEOUT=600000 browserless/chrome:latest
require'ferrum'# flatten: false is the documented workaround for Browserless (#540).# This worked in 0.17.1 but breaks in 0.17.2.browser=Ferrum::Browser.new(url: "http://localhost:3311",flatten: false)# Inspect internal stateputs"Contexts: #{browser.contexts.contexts.keys}"puts"@default_context: #{browser.contexts.instance_variable_get(:@default_context)&.id}"# Attempt 1: fails because @default_context is the implicit contextbeginbrowser.create_pageputs"✅ create_page succeeded"rescueFerrum::BrowserError=>eputs"❌ create_page FAILED: #{e.message}"end# reset doesn't help — conditional clear doesn't apply to implicit contextsbrowser.resetputs"@default_context after reset: #{browser.contexts.instance_variable_get(:@default_context)&.id}"# Attempt 2: still failsbeginbrowser.create_pageputs"✅ create_page after reset succeeded"rescueFerrum::BrowserError=>eputs"❌ create_page after reset FAILED: #{e.message}"endbrowser.quit
With Ferrum 0.17.1 — passes (auto_attach is skipped, no implicit context captured):
Contexts: ["<implicit-context-id>"]
@default_context: <implicit-context-id>
❌ create_page FAILED: Failed to find browser context for id <implicit-context-id>
@default_context after reset: <implicit-context-id>
❌ create_page after reset FAILED: Failed to find browser context for id <implicit-context-id>
3. Cuprite/Capybara (real-world scenario)
With Cuprite using the standard flatten: false workaround for Browserless, all system specs fail:
Ferrum::BrowserError:
Failed to find browser context for id 837C66659427FDF757025C7FD799AE4A
Expected behavior
With flatten: false and a remote Browserless instance, default_context should return a usable, explicitly created browser context — same as in v0.17.1.
Proposed fix
Option A: Restore the flatten guard in auto_attach
The simplest fix — if flatten: false, don't send Target.setAutoAttach:
Describe the bug
After updating
ferrumfrom0.17.1to0.17.2, it seems that all my system specs are failing with:Failed to find browser context for id XXX.To Reproduce
1. Start Browserless (assuming docker)
1. Use Browserless to create a page
You should see:
Failed to find browser context with id XXX (Ferrum::BrowserError)Expected behavior
I should be able to create a page
Desktop:
Additional context
Here is an analysis of the problem by Cursor/Opus 🤖 :
Details
PR #566 (v0.17.2) introduced two changes that together break any setup using
flatten: falsewith a remote Chrome/Browserless:auto_attachlost itsflattenguard. In v0.17.1,auto_attachwas a no-op whenflatten: false:In v0.17.2 (fix:
browser.resettries to dispose default implicit context #540 #566), the guard was removed:Now
auto_attachalways firesTarget.setAutoAttach, which triggersTarget.attachedToTargetCDP events for existing targets. These events calladd_context, which captures the browser's implicit default context and promotes it to@default_contextvia@default_context ||= context. This implicit context is not usable forTarget.createTarget.resetconditionally clears@default_context. In v0.17.1,resetunconditionally set@default_context = nil. In v0.17.2, it only clears it ifTarget.getBrowserContextslists it — but that API never returns implicit contexts. So afterreset,@default_contextstill points to the stale implicit context.The combination means:
@default_contextis the implicit context;create_targetis rejected by Chrome.resetnever clears@default_contextbecause the implicit context isn't in thegetBrowserContextslist.Why
flatten: falsemattersflatten: falseis the documented workaround for using Ferrum/Cuprite with Browserless (see #540 comments). In v0.17.1,flatten: falsealso implicitly preventedauto_attachfrom running, which kept the implicit context out of Ferrum's state. The v0.17.2 removal of the guard broke this.Root cause: the three interacting changes
1.
auto_attach— guard removed (primary cause)With
flatten: false, this was previously a no-op. Now it always runs, causingTarget.attachedToTargetevents that feedadd_context.2.
add_context— promotes implicit context to@default_contextThis preempts
default_context's@default_context ||= create, so a proper explicit context is never created.3.
reset— conditional clear (secondary cause)Target.getBrowserContextsonly returns explicitly created contexts. The implicit context is never in the list, so@default_contextis never cleared between tests.To reproduce
1. Start Browserless
Wait until the service is ready, then verify:
2. Minimal reproduction script
Create
repro.rb(only dependency:gem install ferrum -v 0.17.2):With Ferrum 0.17.1 — passes (auto_attach is skipped, no implicit context captured):
With Ferrum 0.17.2 — fails:
3. Cuprite/Capybara (real-world scenario)
With Cuprite using the standard
flatten: falseworkaround for Browserless, all system specs fail:Expected behavior
With
flatten: falseand a remote Browserless instance,default_contextshould return a usable, explicitly created browser context — same as in v0.17.1.Proposed fix
Option A: Restore the
flattenguard inauto_attachThe simplest fix — if
flatten: false, don't sendTarget.setAutoAttach:This restores v0.17.1 behavior. If the guard was removed intentionally (e.g., to fix another issue), see Option B.
Option B: Don't promote implicit contexts + always clear on reset
If
auto_attachmust always run, then prevent implicit contexts from becoming@default_context:This preserves the #566 fix (not disposing implicit contexts) while ensuring
default_contextalways callscreatefor a usable context.Workaround
Until fixed upstream, prepend a patch in test setup (we use Option B):
Environment
browserless/chrome:latestRelated
browser.resetafter initializing browser while using browserless v2 #540 — Original issue (BrowserError onresetwith Browserless)browser.resettries to dispose default implicit context #540 #566 — PR that introduced this regression (removedflattenguard + conditionalreset)dispose) that was superseded by fix:browser.resettries to dispose default implicit context #540 #566