openclaw - 💡(How to fix) Fix Browser plugin: _snapshotForAI missing against Playwright 1.53+ (ariaSnapshot); 'Restart the gateway' error is misleading for dep mismatches [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#68921Fetched 2026-04-20 12:04:24
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Participants

Error Message

Error: refs=aria requires Playwright _snapshotForAI support.

Fix Action

Fix / Workaround

Workaround in place

Until this ships I'm running a ~40-line Node --require shim via a systemd drop-in that adds a backward-compat _snapshotForAI to Page.prototype delegating to ariaSnapshot. Fine for a workaround, but ideally the plugin itself no longer depends on a renamed internal.

Code Example

Error: refs=aria requires Playwright _snapshotForAI support.

---

// site 1 — generic snapshot
const maybe = page;
if (!maybe._snapshotForAI) throw new Error("Playwright _snapshotForAI is not available. Upgrade playwright-core.");
let snapshot = (await maybe._snapshotForAI({
    timeout: Math.max(500, Math.min(6e4, Math.floor(opts.timeoutMs ?? 5e3))),
    track: "response"
}))?.full ?? "";

// site 2 — refs=aria mode
if (!maybe._snapshotForAI) throw new Error("refs=aria requires Playwright _snapshotForAI support.");
const built = buildRoleSnapshotFromAiSnapshot((await maybe._snapshotForAI({
    timeout: 5e3,
    track: "response"
}))?.full ?? "", opts.options);

---

-  if (!maybe._snapshotForAI) throw new Error("...");
-  (await maybe._snapshotForAI({timeout, track: "response"}))?.full
+  if (!maybe.ariaSnapshot && !maybe._snapshotForAI) throw new Error("...");
+  (maybe.ariaSnapshot
+    ? (await maybe.ariaSnapshot({timeout, _track: "response"}))
+    : (await maybe._snapshotForAI({timeout, track: "response"}))?.full)
RAW_BUFFERClick to expand / collapse

What happens

The browser plugin's AI-snapshot code path (dist/pw-ai-*.js) calls page._snapshotForAI(...) against the playwright-core Page instance. That method is an internal API that Playwright deprecated/renamed in 1.53 and removed by 1.59; it is now the public ariaSnapshot(). Return shape also changed — old returned {full: string}, new returns a bare string.

Installing openclaw in an environment where playwright-core resolves to ≥ 1.53 (my install has 1.59.1, bundled via openclaw's own node_modules/playwright-core) means every refs=aria tool call throws at the guard:

Error: refs=aria requires Playwright _snapshotForAI support.

before the request ever reaches Chrome. CDP, Chrome itself, and the browser control service are all healthy; the problem is purely in the plugin's JS.

Why it looks like "the bridge keeps falling"

session-tab-registry-*.js wraps Playwright timeouts (and any error containing timed out|timeout|aborted) with BROWSER_TOOL_MODEL_HINT:

"Do NOT retry the browser tool — it will keep failing. Use an alternative approach or inform the user that the browser is currently unavailable. Restart the OpenClaw gateway."

In a dependency-mismatch scenario, the recommended restart cannot fix it. The agent restarts, the plugin comes back, the same missing method throws again on the next snapshot call. Users experience this as "the bridge keeps falling," and the suggested recovery action is actively wrong — restarts just replay the same failure.

Where the calls are

In the minified dist/pw-ai-*.js (hashed filename, currently pw-ai-BJRFEth4.js), two call sites:

// site 1 — generic snapshot
const maybe = page;
if (!maybe._snapshotForAI) throw new Error("Playwright _snapshotForAI is not available. Upgrade playwright-core.");
let snapshot = (await maybe._snapshotForAI({
    timeout: Math.max(500, Math.min(6e4, Math.floor(opts.timeoutMs ?? 5e3))),
    track: "response"
}))?.full ?? "";

// site 2 — refs=aria mode
if (!maybe._snapshotForAI) throw new Error("refs=aria requires Playwright _snapshotForAI support.");
const built = buildRoleSnapshotFromAiSnapshot((await maybe._snapshotForAI({
    timeout: 5e3,
    track: "response"
}))?.full ?? "", opts.options);

Suggested fix

Prefer ariaSnapshot when present, fall back to _snapshotForAI for older Playwright. Diff shape for each site:

-  if (!maybe._snapshotForAI) throw new Error("...");
-  (await maybe._snapshotForAI({timeout, track: "response"}))?.full
+  if (!maybe.ariaSnapshot && !maybe._snapshotForAI) throw new Error("...");
+  (maybe.ariaSnapshot
+    ? (await maybe.ariaSnapshot({timeout, _track: "response"}))
+    : (await maybe._snapshotForAI({timeout, track: "response"}))?.full)

Note: ariaSnapshot accepts _track (underscore) as the track arg in 1.59.1, and Locator.ariaSnapshot() is already used elsewhere in the same file (the selector-scoped path at line ~1129 is fine — it's Page-level that's broken).

Secondary: improve the error-hint wrapper

BROWSER_TOOL_MODEL_HINT / resolveBrowserFetchOperatorHint wraps Playwright timeouts with "Restart the OpenClaw gateway." For actual control-service unreachability this is correct, but for in-process Playwright errors (stale pages, missing prototype methods, locator timeouts from detached frames) it teaches the agent to attempt a recovery that never helps. Consider distinguishing transport failures from operation failures so only the former get the "restart gateway" hint.

Environment

  • openclaw 2026.4.15
  • playwright-core 1.59.1 (resolved from node_modules/playwright-core under the global openclaw install)
  • Node 22.x
  • Linux / systemd user service

Workaround in place

Until this ships I'm running a ~40-line Node --require shim via a systemd drop-in that adds a backward-compat _snapshotForAI to Page.prototype delegating to ariaSnapshot. Fine for a workaround, but ideally the plugin itself no longer depends on a renamed internal.

Happy to PR the two-site fix if it'd be useful — want to check whether you'd prefer the ariaSnapshot-preferred branch I sketched above or a cleaner "use only new API + bump playwright-core peerDep floor" approach.

extent analysis

TL;DR

Update the browser plugin's AI-snapshot code path to prefer ariaSnapshot when present and fall back to _snapshotForAI for older Playwright versions.

Guidance

  • Identify the two call sites in dist/pw-ai-*.js where _snapshotForAI is used and update them to use ariaSnapshot when available.
  • Modify the error handling to distinguish between transport failures and operation failures, and provide a more accurate error message for the latter.
  • Consider bumping the playwright-core peer dependency floor to ensure compatibility with the updated code.
  • Test the updated code with different Playwright versions to ensure backward compatibility.

Example

The suggested fix provides a code snippet that demonstrates how to update the call sites:

-  if (!maybe._snapshotForAI) throw new Error("...");
-  (await maybe._snapshotForAI({timeout, track: "response"}))?.full
+  if (!maybe.ariaSnapshot && !maybe._snapshotForAI) throw new Error("...");
+  (maybe.ariaSnapshot
+    ? (await maybe.ariaSnapshot({timeout, _track: "response"}))
+    : (await maybe._snapshotForAI({timeout, track: "response"}))?.full)

Notes

The provided workaround using a Node --require shim is a temporary solution and should be replaced with a proper update to the plugin code.

Recommendation

Apply the suggested fix to update the browser plugin's AI-snapshot code path to use ariaSnapshot when available, and fall back to _snapshotForAI for older Playwright versions. This approach ensures backward compatibility and allows for a smoother transition to the new API.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING