Skip to content

fix: stop stale refs from silently no-oping and suggest the current ref - #342

Merged
nicobailon merged 4 commits into
mainfrom
fix/issue340-stale-refs
Sep 29, 2026
Merged

nicobailon merged 4 commits into
mainfrom
fix/issue340-stale-refs

Conversation

@nicobailon

Copy link
Copy Markdown
Owner

A ref whose element was re-rendered usually didn't fail. surf click e4 printed OK and did nothing. Surf kept the removed node reachable through window.__piRefs, so the click went to an element no longer on the page. On pages where handlers sit on the document (React), nothing happened. The "not found" error only appeared after garbage collection.

Now a ref works only if its element is still on the page. When it isn't, the error suggests the current element when exactly one visible element has the same role and accessible name:

Element e12 no longer exists. Did you mean e40 (button "Save")? Otherwise run surf read.

With zero or several matches it says to run surf read. It never suggests an element with a different role or name, or one inside an aria-hidden subtree.

  • All 11 ref-taking actions use one resolver.
  • locate.role, locate.text and locate.label now record the element's real role and name for its ref instead of the search text, so their refs get correct suggestions.
  • The accessible-name function moves out of generateAccessibilityTree, and the identical copy in generateYamlTree is deleted, so suggestion names match surf read output. read output is unchanged.
  • Guarded semantic click/fill with a ref that doesn't exist returns stale_observation, which the semantic CLI already refreshes and retries.

Refs that survive re-renders are deferred. Checking real sites: keyed React updates (sorting, tabs, react-select, controlled inputs) keep their nodes. A Vue list filter and restore replaced 419 of 499 nodes, and a react.dev page change replaced 583 of 623. Many replaced elements share a role and name: 210 of 419 and only 9 of 208 had a unique match. Carrying refs over automatically would often pick the wrong element. Revisit if the "Did you mean" error shows up often in real agent runs.

Tests: unit tests for a swapped button, different role or name, several matches, unknown refs, locate refs with a partial name, and an aria-hidden container. A real-Chrome e2e case checks the suggestion and that clicking the suggested ref works. Full unit suite, check, lint and real-Chrome e2e pass locally under Node 24.

Closes #340

Comment thread src/content/accessibility-tree.ts Fixed
@nicobailon
nicobailon merged commit f54678c into main Sep 29, 2026
8 checks passed
@nicobailon
nicobailon deleted the fix/issue340-stale-refs branch September 29, 2026 05:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Element refs break when the page re-renders

2 participants