Summary
Any command that evaluates script against a browsing context fails if it lands in the instant that
context is being replaced by a navigation. The error is always:
com.vibium.errors.VibiumException: failed to parse script result: no result member
at com.vibium.internal.BiDiClient.mapError(BiDiClient.java:240)
at com.vibium.internal.BiDiClient.dispatchLine(BiDiClient.java:193)
at com.vibium.internal.BiDiClient.receiveLoop(BiDiClient.java:163)
This is not specific to clicking, to a particular page, or to cross-origin navigation. It reproduces
on a plain same-origin page with no application framework involved.
Reproduction
Start a navigation, then issue page.url() as fast as the transport allows. No application code, no
click, no popup:
page.go(BASE + "/some/page");
for (int round = 0; round < 10; round++) {
// start a same-origin navigation from inside the page
page.evaluate("window.location = '" + BASE + "/some/page?r=" + round + "'");
// then race it for 3 seconds
final long deadline = System.currentTimeMillis() + 3000;
while (System.currentTimeMillis() < deadline) {
try {
page.url();
} catch (RuntimeException e) {
// VibiumException: failed to parse script result: no result member
}
}
page.waitForLoad();
}
Result:
|
|
| rounds producing at least one failure |
10 of 10 |
total page.url() calls |
13,724 |
| total failures |
10 — exactly one per navigation |
Exactly one failure per navigation is the shape of the defect: there is a single instant in which a
command can land, and a tight poll hits it exactly once.
Why page.url() is a script command
url() is not a protocol-level read — it goes through the same decoder as everything else:
vibium:page.url
→ Router.handlePageURL (clicker/internal/api/handlers_navigation.go:99)
→ GetURL (handlers_navigation.go:304)
→ EvalSimpleScript(s, context, "() => window.location.href")
→ bidi.ParseScriptResponse (clicker/internal/bidi/script.go:106)
GetTitle (:309) and GetContent (:314) are the same shape, and so is every actionability
check. So the exposure is not one API — it is anything that evaluates script while a navigation is
in flight.
Where this shows up in real use
Two independent cases in our suite, both now explained by the above:
- A cart page's checkout button fails ~67% of the time. Clicking
#btn-secure-checkout-top and then calling page.waitForLoad(): 37 of 55 real-page runs
failed (8/10 standalone, 20/35 on Grid, 9/10 local browser). The click starts a navigation and the
commands that follow land in the window.
- Reading a PayPal popup out of
about:blank. The popup opens blank and navigates to the
provider a moment later; polling popup.url() to wait for that threw the same error in 4 runs
of 4, with no click anywhere in the flow.
What never fails is equally informative:
page.go(url) — 0 failures in 36 — because the client waits the navigation out before issuing
anything else.
- A different button on the same application (
#nextlinkdiv) that also replaces the document on
click, exercised dozens of times. Verified it really does navigate, with a marker a navigation
would destroy:
page.evaluate("window.__navProbe = 'set'");
click("#nextlinkdiv");
page.evaluate("typeof window.__navProbe"); // → "undefined": the document was replaced
So whether a given flow fails depends on when it issues its next command relative to the
navigation, not on the control being clicked.
Relationship to #336
#336 is why this is opaque rather than self-diagnosing. ParseScriptResponse has a result branch and
an exception branch but no error-envelope branch, so a BiDi error response — which we would
expect to say the context was destroyed or navigated — lands on the "no result member" path and the
real message is discarded. Every cause collapses to the same string, so a caller cannot tell a
recoverable navigation race from a genuinely malformed response. With #336 fixed, this issue should
name its own cause.
Relationship to #289 / #291 and PR #29
This looks like the same class of race that #289 / #291 fixed in the capture path, where a BiDi
command issued into an in-flight navigation goes unanswered. #291 measured the window — "the
navigation an action triggers is not reported until ~10ms after that action's command returns" — and
fixed it with captureWithNavigationRetry. Our build contains that fix; the script path appears to
have no equivalent, and the reproduction above is that gap made deterministic.
PR #29 ("optional auto-waiting on navigation after action") would likely close the window for the
action case, but not for a bare read like url() issued by application code.
Environment
Note on this report's history
This issue has been rewritten three times now as the diagnosis improved, and the earlier framings are wrong:
it was first reported as "a click that navigates on a script-heavy page", then narrowed to "one
page's checkout button, while other navigating clicks are fine". Both were field observations
without a reproduction. Nine synthetic scenarios failed to reproduce it because each one clicked and
then waited — none issued a command into the navigation window, which turns out to be the only
thing that matters. A disableForm() call we had flagged as the distinguishing feature of the
failing control was a red herring; synthesising that shape did not reproduce it.
Summary
Any command that evaluates script against a browsing context fails if it lands in the instant that
context is being replaced by a navigation. The error is always:
This is not specific to clicking, to a particular page, or to cross-origin navigation. It reproduces
on a plain same-origin page with no application framework involved.
Reproduction
Start a navigation, then issue
page.url()as fast as the transport allows. No application code, noclick, no popup:
Result:
page.url()callsExactly one failure per navigation is the shape of the defect: there is a single instant in which a
command can land, and a tight poll hits it exactly once.
Why
page.url()is a script commandurl()is not a protocol-level read — it goes through the same decoder as everything else:GetTitle(:309) andGetContent(:314) are the same shape, and so is every actionabilitycheck. So the exposure is not one API — it is anything that evaluates script while a navigation is
in flight.
Where this shows up in real use
Two independent cases in our suite, both now explained by the above:
#btn-secure-checkout-topand then callingpage.waitForLoad(): 37 of 55 real-page runsfailed (8/10 standalone, 20/35 on Grid, 9/10 local browser). The click starts a navigation and the
commands that follow land in the window.
about:blank. The popup opens blank and navigates to theprovider a moment later; polling
popup.url()to wait for that threw the same error in 4 runsof 4, with no click anywhere in the flow.
What never fails is equally informative:
page.go(url)— 0 failures in 36 — because the client waits the navigation out before issuinganything else.
#nextlinkdiv) that also replaces the document onclick, exercised dozens of times. Verified it really does navigate, with a marker a navigation
would destroy:
So whether a given flow fails depends on when it issues its next command relative to the
navigation, not on the control being clicked.
Relationship to #336
#336 is why this is opaque rather than self-diagnosing.
ParseScriptResponsehas a result branch andan exception branch but no error-envelope branch, so a BiDi error response — which we would
expect to say the context was destroyed or navigated — lands on the "no result member" path and the
real message is discarded. Every cause collapses to the same string, so a caller cannot tell a
recoverable navigation race from a genuinely malformed response. With #336 fixed, this issue should
name its own cause.
Relationship to #289 / #291 and PR #29
This looks like the same class of race that #289 / #291 fixed in the capture path, where a BiDi
command issued into an in-flight navigation goes unanswered. #291 measured the window — "the
navigation an action triggers is not reported until ~10ms after that action's command returns" — and
fixed it with
captureWithNavigationRetry. Our build contains that fix; the script path appears tohave no equivalent, and the reproduction above is that gap made deterministic.
PR #29 ("optional auto-waiting on navigation after action") would likely close the window for the
action case, but not for a bare read like
url()issued by application code.Environment
26.5.31-browser-clouds— local build ofbrowser-clouds@0935b943, which containsRoute every BiDi script result through one decoder (#221, #124) #253 and the Recording: navigating actions stall 5s on a swallowed screenshot timeout #289/Stop filmstrip captures from stalling on an in-flight navigation (#289) #291 capture fix
Note on this report's history
This issue has been rewritten three times now as the diagnosis improved, and the earlier framings are wrong:
it was first reported as "a click that navigates on a script-heavy page", then narrowed to "one
page's checkout button, while other navigating clicks are fine". Both were field observations
without a reproduction. Nine synthetic scenarios failed to reproduce it because each one clicked and
then waited — none issued a command into the navigation window, which turns out to be the only
thing that matters. A
disableForm()call we had flagged as the distinguishing feature of thefailing control was a red herring; synthesising that shape did not reproduce it.