Skip to content

Handle ChromeDriver detached-document errors during selector visibility checks - #5829

Open
GlazerMann wants to merge 3 commits into
OSC:masterfrom
GlazerMann:patch11
Open

GlazerMann wants to merge 3 commits into
OSC:masterfrom
GlazerMann:patch11

Conversation

@GlazerMann

@GlazerMann GlazerMann commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Fixes #4725.

ChromeDriver can intermittently report an element from a replaced document as:

Selenium::WebDriver::Error::UnknownError:
Node with given id does not belong to the document

rather than the stale-element error Capybara normally knows how to recover from.

The failure recorded in #4725 occurs specifically while Capybara evaluates selector visibility:

ChromeNode#visible?
  → Element#visible?
  → SelectorQuery#matches_visibility_filters?
  → SelectorQuery#matches_system_filters?
  → SelectorQuery#matches_filters?

This change handles that confirmed OOD failure at the narrowest useful boundary. When this exact ChromeDriver error occurs while evaluating a Capybara::Selenium::ChromeNode, the detached selector candidate is treated as a non-match. Capybara's surrounding synchronized query can then continue resolving the selector against the current document.

Scope and safety

The workaround is deliberately narrow.

  • It applies only to Chrome selector candidates.
  • It handles only Selenium::WebDriver::Error::UnknownError containing the specific message Node with given id does not belong to the document.
  • It does not add UnknownError to Capybara's general invalid_element_errors.
  • It does not broaden Node::Base#synchronize.
  • It does not automatically replay click, set, send_keys, submit, or other side-effecting WebDriver operations.
  • Unrelated Chrome UnknownErrors continue to propagate.
  • The same error from non-Chrome selector candidates continues to propagate.
  • Errors raised by custom selector filters continue to propagate normally.
  • Existing stale-element handling remains unchanged.

The distinction between selector evaluation and WebDriver actions is intentional.

A candidate belonging to a replaced document cannot satisfy the current selector, so treating that candidate as a non-match is appropriate at this layer. In contrast, when ChromeDriver reports an error from a side-effecting action, the error alone does not establish whether the action already occurred. Automatically retrying such an operation could duplicate clicks, form submissions, keystrokes, or other effects.

Deliberate non-coverage

This PR does not assume that every occurrence of this ChromeDriver error originates in visibility filtering.

Capybara's Selenium lookup also contains read-only pre-filter optimizations such as filter_by_text and gather_hints, which can execute against element references before SelectorQuery#matches_filters? runs.

The failure recorded in #4725 does not originate from those paths, so this PR intentionally does not patch them.

If OOD later observes the same ChromeDriver error from one of those optimization paths, that case should be handled separately by abandoning the optional optimization and returning to normal selector processing rather than making UnknownError generally retryable.

Likewise, future occurrences in other read-only query paths should be evaluated from their actual stack traces rather than assuming all instances of this ChromeDriver message have identical retry semantics.

Why a selector non-match is preferable here

Returning false may allow the surrounding Capybara query to continue until the normal selector timeout if no valid replacement element appears.

That is intentional.

At the visibility-filter boundary, the stale candidate cannot represent a valid result from the current document. If no replacement candidate appears, the appropriate result is therefore Capybara's normal selector failure or timeout rather than an internal ChromeDriver node-reference error.

This keeps the workaround within normal query semantics without changing retry behavior for browser actions.

Compatibility and self-retirement checks

This workaround relies on a private Capybara method, so the test suite contains explicit checks that flag dependency or upstream-behavior changes requiring review.

The checks cover:

  • the Capybara version changing from the version against which the workaround was validated;
  • ChromeNode gaining upstream error handling relevant to this condition;
  • changes to the private matches_visibility_filters? method signature; and
  • whether stock Capybara still propagates the injected detached-document error when the OOD prepend is deliberately bypassed.

The semantic canary is intended to make the workaround easier to retire. If upstream Capybara begins handling this exact visibility-filter case itself, the test suite will fail with an explicit message instructing maintainers to review and remove the workaround.

The private-method signature check remains fail-closed because blindly applying a prepend after an incompatible private API change could break selector behavior throughout the system test suite.

These checks detect Capybara/API behavior changes. They cannot prove that a future ChromeDriver has stopped emitting this error altogether, because the unit test deliberately injects the error rather than depending on reproducing a timing race.

Regression coverage

Unit tests verify that:

  • the confirmed Chrome detached-document visibility error becomes a selector non-match;
  • matching does not depend on ChromeDriver's surrounding inspector-error JSON formatting;
  • unrelated Chrome UnknownErrors remain visible;
  • UnknownError is not classified as a general Capybara invalid-element error;
  • the same message from a non-Chrome candidate remains visible;
  • custom selector-filter failures are not swallowed;
  • standard stale-element selector behavior is preserved;
  • successful visible selector matches are unchanged;
  • visible: false behavior is unchanged;
  • detached-document errors during obscured checks are handled at the same selector boundary; and
  • upstream or dependency changes that may make the workaround obsolete are surfaced explicitly.

Reproduction and validation

The original intermittent failure is documented in #4725 in:

ProjectManagerTest#test_create_with_invalid_icon_triggers_alert

The recorded failure used Chrome 140.0.7339.207, selenium-webdriver 4.26.0, and Capybara 3.40.0.

The stack trace from that failure reaches ChromeNode#visible? and SelectorQuery#matches_visibility_filters?, which is the exact boundary patched here.

Because this is a timing-dependent browser race, the regression tests inject the failure deterministically rather than introducing a deliberately flaky browser-level CI test. Repeated execution of the affected project-manager system test remains useful as a stress validation step.

Upstream context

Related reports exist in:

  • teamcapybara/capybara#2800
  • SeleniumHQ/selenium#15401

These issues provide related evidence for the same Chrome detached-document error family, but they should not be read as proof that every reported occurrence follows the same code path as OOD.

The exact OOD call path addressed by this PR is established independently by the stack trace in #4725.

Newer Capybara code has added Chrome-specific handling for this error in some paths, but reports have continued through later Chrome and Selenium versions and through paths not necessarily covered by a ChromeNode-only change. OOD therefore keeps this workaround tied to the behavior and private API it has explicitly validated.

A Chrome feature-flag workaround involving DeferRendererTasksAfterInput has reduced the problem for some users, but later reports indicate that it does not eliminate the failure consistently. This PR therefore does not alter Chrome scheduling behavior.

The shim should be removed once OOD verifies that its supported Capybara, Selenium, and ChromeDriver combination no longer requires it. The test suite includes a canary that flags upstream behavior changes that may make the workaround obsolete.

@github-project-automation github-project-automation Bot moved this to Awaiting Review in PR Review Pipeline Sep 22, 2026
@GlazerMann
GlazerMann marked this pull request as draft September 22, 2026 17:32
@GlazerMann GlazerMann changed the title deal with upstream bugs Handle ChromeDriver detached-document visibility races in system tests Sep 22, 2026
@GlazerMann GlazerMann changed the title Handle ChromeDriver detached-document visibility races in system tests Handle ChromeDriver detached-document errors during selector visibility checks Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Awaiting Review

Development

Successfully merging this pull request may close these issues.

Correct intermittent project manager test

2 participants