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
{{ message }}
Repository navigation
browser.click/get_text always fail with ref_not_found right after a fresh browser.snapshot #121
browser.click and browser.get_text always fail with ref_not_found, even immediately after a fresh browser.snapshot returns a valid ref tree with a nonzero refCount. Confirmed this is not related to the CLI, PowerShell, connection reuse, or timing - reproduced by talking to the named pipe directly.
Repro steps (raw JSON-RPC over the named pipe, bypassing the CLI entirely)
Using a single persistent TCP connection to \\.\pipe\wmux (so it's not a "new connection per request" issue):
Immediately (same connection, no delay) send {"method":"browser.click","params":{"ref":"e2","caller":"<same-surface-id>"},"id":2,"token":"<pipe-token>"}
-> returns {"error":{"code":-32000,"message":"ref_not_found"}}
Also tried via the CLI (wmux browser snapshot then wmux browser click e2) - same result.
What I ruled out
Not a connection-lifetime issue: sent snapshot+click over the SAME socket without closing it between requests - still ref_not_found.
Not a timing issue: sent click with zero artificial delay right after snapshot - still fails. Also tried inside one long-lived Node process reusing the connection.
Not a caller/surface mismatch: explicitly passed the same caller (browser surface id, matching WMUX_SURFACE_ID / the id returned by list-surfaces for the type: "browser" entry) to both calls.
Not a ref format issue: tried "e2", "2", 2, and "@e2" as the ref value. All bare formats fail with ref_not_found; only the @-prefixed form fails differently, with Invalid parameters (consistent with docs saying refs take no @ prefix).
browser.get_text with the same ref also fails with ref_not_found, so this isn't click-specific - it looks like every ref-consuming command can't resolve refs that browser.snapshot just generated.
Environment
wmux (Windows), CLI at resources/cli/wmux.js
open, snapshot, screenshot, eval all work correctly - only ref-based interaction commands (click, get_text, presumably type/fill/wait) are affected.
Expected
browser.click (and other ref-based commands) should successfully resolve a ref returned by the immediately preceding browser.snapshot on the same browser surface.
Workaround
browser.eval with direct DOM JS (document.querySelector(...).click(), manual value + dispatchEvent('input')) works reliably and is what I'm using in the meantime.
Your investigation was right on every single count, and that's what made this findable. Not a connection lifetime issue, not timing, not a caller mismatch — and once all three are ruled out, what's left is that the map never had a key called e2 in the first place.
The bug
buildAccessibilityTree keys its ref map with the display form the snapshot tree prints:
constref=`@e${refCounter}`;refMap.set(ref,{ nodeId, backendNodeId });// key is "@e2"
resolveRef then looked it up verbatim — so only the exact string @e2 matched. The CLI (wmux browser click e2), the orchestrator reference and every doc example pass the bare e2. Nothing that went through a normal path could ever resolve, which is why it hit click, type, fill, get_text and wait uniformly rather than looking like a per-command bug.
And @e2 was not a workaround, which you also found. That's PowerShell: a leading @ is the splatting operator, so the argument is mangled by the shell before wmux sees it. Our own orchestrator reference has a "Sharp edges" note telling people to drop the @ for exactly that reason — which, given the map was keyed with the @, meant the docs were confidently steering everyone into the one form that could never work.
The fix
Refs are normalized to the canonical key before lookup, so e2, @e2, 2, E2 and e002 all resolve to the same node. The bare form stays the documented one, because it's the one that survives every shell.
ref_not_found also says something useful now. It used to be a bare token, which is what sent you hunting connection lifetimes; it now distinguishes the two real causes:
ref_not_found: no snapshot yet for this browser — run browser.snapshot first
ref_not_found: e400 — the last snapshot of this browser has @e1..@e300
ref_not_found: "submit" is not a ref — expected e12 or @e12
Tests pin both spellings against a map built by a real buildAccessibilityTree run, so the display form and the lookup form can't drift apart again.
Still true after this
The staleness caveat is unchanged and unrelated: against client-rendered SPAs, refs can genuinely go stale between the snapshot and the click because the DOM was re-rendered underneath. browser.eval with a DOM query stays the right fallback there — and the user still watches every action live in the panel, which is the point of driving the browser this way at all.
Thanks for the report. The raw-pipe repro that bypassed the CLI entirely is what turned this from "someone's shell is weird" into a one-line root cause.
Activity
amirlehmam commentedon Jul 28, 2026
Fixed in 7a3973e, shipping in v0.37.0.
Your investigation was right on every single count, and that's what made this findable. Not a connection lifetime issue, not timing, not a caller mismatch — and once all three are ruled out, what's left is that the map never had a key called
e2in the first place.The bug
buildAccessibilityTreekeys its ref map with the display form the snapshot tree prints:resolveRefthen looked it up verbatim — so only the exact string@e2matched. The CLI (wmux browser click e2), the orchestrator reference and every doc example pass the baree2. Nothing that went through a normal path could ever resolve, which is why it hitclick,type,fill,get_textandwaituniformly rather than looking like a per-command bug.And
@e2was not a workaround, which you also found. That's PowerShell: a leading@is the splatting operator, so the argument is mangled by the shell before wmux sees it. Our own orchestrator reference has a "Sharp edges" note telling people to drop the@for exactly that reason — which, given the map was keyed with the@, meant the docs were confidently steering everyone into the one form that could never work.The fix
Refs are normalized to the canonical key before lookup, so
e2,@e2,2,E2ande002all resolve to the same node. The bare form stays the documented one, because it's the one that survives every shell.ref_not_foundalso says something useful now. It used to be a bare token, which is what sent you hunting connection lifetimes; it now distinguishes the two real causes:Tests pin both spellings against a map built by a real
buildAccessibilityTreerun, so the display form and the lookup form can't drift apart again.Still true after this
The staleness caveat is unchanged and unrelated: against client-rendered SPAs, refs can genuinely go stale between the snapshot and the click because the DOM was re-rendered underneath.
browser.evalwith a DOM query stays the right fallback there — and the user still watches every action live in the panel, which is the point of driving the browser this way at all.Thanks for the report. The raw-pipe repro that bypassed the CLI entirely is what turned this from "someone's shell is weird" into a one-line root cause.
fix: browser refs, drop marker, in-app update, dead popup links (#123 #…
fix(browser): resolve the bare `eN` refs every caller actually sends