Skip to content

fix(browser): keep upload errors specific#101465

Merged
steipete merged 1 commit into
mainfrom
codex/browser-upload-file-chooser
Jul 7, 2026
Merged

fix(browser): keep upload errors specific#101465
steipete merged 1 commit into
mainfrom
codex/browser-upload-file-chooser

Conversation

@steipete

@steipete steipete commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Closes #38844.

Browser uploads already support an atomic chooser path—send paths and the trigger ref in one request—but the agent-facing guidance still encouraged a split arm-then-click flow. On dynamic pages, that creates an avoidable window for a snapshot ref to go stale.

The direct browser client also gave file-chooser and dialog hooks a fixed 20-second outer watchdog even though their advertised Playwright operation timeout defaults to 120 seconds. When the outer watchdog won, callers could receive a generic browser-control timeout/restart message instead of the specific stale-ref or Playwright operation error.

Current main has already improved dispatcher error preservation and browser-act timeout slack since the original 2026.3.2 report. This change closes the remaining hook-specific mismatch and makes the atomic upload contract visible to agents and operators.

Why This Change Was Made

  • Tell agents to send chooser trigger ref and paths in the same upload call when available.
  • Keep paths-only arming for deliberate delayed-trigger workflows; no existing upload mode is removed.
  • Keep direct inputRef and element uploads unchanged.
  • Reuse one operation-timeout-plus-5-second-slack helper for downloads, file chooser hooks, and dialog hooks, so the browser operation reports first.
  • Update the CLI docs with the atomic --ref form and the compatibility rule.

The exact pinned Playwright 1.61.1 contract was checked: page.waitForEvent("filechooser", { timeout }) owns the chooser timeout and rejects on page crash/close, while FileChooser.setFiles() delegates to the file input operation. The outer client must therefore stay alive beyond that operation deadline rather than race it at 20 seconds.

User Impact

Dynamic-page uploads are less likely to fail from a stale trigger ref, and real stale-ref/action errors stay actionable instead of being masked as browser-control reachability failures. Scripts that intentionally arm with paths first and click later continue to work.

Evidence

Remote provider: Blacksmith Testbox, lease tbx_01kwxpxmb3x1g1prnaa9cs4230 (silver-prawn).

  • pnpm docs:list — completed before docs validation.
  • pnpm test extensions/browser/src/browser/client-actions-core.hooks.test.ts extensions/browser/src/browser/client-actions-core.downloads.test.ts extensions/browser/src/browser/server.agent-contract-form-layout-act-commands.test.ts extensions/browser/src/browser/pw-tools-core.screenshots-element-selector.test.ts extensions/browser/src/browser-tool.test.ts — 130 passed.
  • pnpm check:changed -- <touched browser/docs files> — production/test typechecks, changed-file lint, repository guards, docs lane, and import-cycle checks passed.
  • Fresh Codex autoreview (gpt-5.5, high) reported no actionable findings.

Regression tests prove explicit atomic uploads receive operation timeout plus transport slack, paths-only arming remains valid with the 120-second default, dialog hooks use the same deadline contract, and the agent description recommends the atomic form.

One broader extensions/browser/src/browser/client.test.ts run exposes an unrelated current-main test-double failure (response.arrayBuffer is not a function) after the bounded-response reader change; 133 other tests in that run passed. This PR does not alter that stale test harness.

Live Dev Gateway + real OpenAI agent + managed Chromium dynamic-page proof is still pending. This PR does not claim that proof yet and should not land until it is added in a follow-up comment.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation size: S maintainer Maintainer-authored PR labels Jul 7, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a48a7026e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

timeoutMs: opts.timeoutMs,
}),
timeoutMs: 20000,
timeoutMs: resolveBrowserOperationRequestTimeoutMs(opts.timeoutMs),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for the trigger click before shortening upload waits

When an atomic upload includes ref and a small timeoutMs (for example 1000ms), this changed watchdog becomes only timeoutMs + 5000, but the server route applies that timeout only to armFileUploadViaPlaywright; the subsequent clickViaPlaywright in extensions/browser/src/browser/routes/agent.act.hooks.ts is called without timeoutMs and falls back to the 8000ms interaction default from act-policy.ts. For a stale/hidden trigger ref, the client can still abort first and return the generic browser-control timeout this change is trying to avoid. Either include the trigger-click timeout/default in this outer timeout calculation or pass the upload timeout through to the trigger click.

Useful? React with 👍 / 👎.

@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 7, 2026, 4:15 AM ET / 08:15 UTC.

Summary
The branch updates Browser upload guidance/docs, changes file-chooser and dialog hook client timeouts to operation timeout plus 5s slack, adds focused hook-client tests, and adds a changelog entry.

PR surface: Source -1, Tests +71, Docs +2. Total +72 across 6 files.

Reproducibility: no. high-confidence live reproduction was run in this review. Source inspection gives a clear reproduction for the review finding: an atomic upload with ref and a small explicit timeoutMs can have a client watchdog shorter than the server-side trigger click default.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: extensions/browser/src/browser/client-actions-core.hooks.test.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #38844
Summary: This PR is the candidate fix for the open Browser upload/file chooser issue; a previously mentioned selector/batch PR was an adjacent mitigation and closed unmerged.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦪 silver shellfish
Patch quality: 🦪 silver shellfish
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Pass the upload timeout through to the trigger click or account for the click default in the client watchdog.
  • [P1] Add redacted live Dev Gateway plus managed Chromium dynamic-page proof showing the upload error stays specific.
  • Remove the normal-PR CHANGELOG.md edit.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body provides focused test/check output but explicitly says live Dev Gateway, real agent, and managed Chromium dynamic-page proof is still pending, so real behavior proof is not yet sufficient before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P2] Merging without the timeout repair can leave the stale-ref masking bug in the new atomic upload path whenever an explicit hook timeout is smaller than the default trigger-click timeout.
  • [P1] Live Dev Gateway, real agent, and managed Chromium dynamic-page proof is still absent, so the runtime reliability claim remains unproven outside focused tests.
  • [P1] The CHANGELOG.md entry conflicts with OpenClaw release-owned changelog policy for normal PRs.

Maintainer options:

  1. Decide the mitigation before merge
    Keep the compatibility-preserving atomic upload direction, but make the hook watchdog cover both chooser arming and trigger click, remove the release-owned changelog edit, and add redacted live browser proof before merge.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P2] Human review remains needed because the PR has a blocking timeout-path finding and self-declared missing live behavior proof; ClawSweeper should not queue repair around missing contributor proof.

Security
Cleared: The diff does not change dependencies, workflows, permissions, secret handling, or upload path validation, and no concrete security or supply-chain concern was found.

Review findings

  • [P2] Account for the trigger click timeout — extensions/browser/src/browser/client-actions-core.ts:159
Review details

Best possible solution:

Keep the compatibility-preserving atomic upload direction, but make the hook watchdog cover both chooser arming and trigger click, remove the release-owned changelog edit, and add redacted live browser proof before merge.

Do we have a high-confidence way to reproduce the issue?

No high-confidence live reproduction was run in this review. Source inspection gives a clear reproduction for the review finding: an atomic upload with ref and a small explicit timeoutMs can have a client watchdog shorter than the server-side trigger click default.

Is this the best way to solve the issue?

No, not yet. The atomic guidance and hook slack are the right direction, but the implementation must include the trigger-click timeout/default in the watchdog calculation and provide live browser proof before merge.

Full review comments:

  • [P2] Account for the trigger click timeout — extensions/browser/src/browser/client-actions-core.ts:159
    When atomic upload includes ref and a small timeoutMs, this line keeps the HTTP client alive for only timeoutMs + 5000, but the server route then calls clickViaPlaywright without passing timeoutMs, so the click falls back to the 8000ms interaction default. A stale or hidden trigger can still make the client abort first and return the generic browser-control timeout this PR is trying to avoid; pass the upload timeout through to the trigger click or include that click/default in the outer watchdog calculation.
    Confidence: 0.9

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 82b0f7cdc88d.

Label changes

Label changes:

  • add P2: This is a normal-priority Browser reliability fix with a bounded upload-hook correctness blocker and no evidence of a core outage.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦪 silver shellfish and patch quality is 🦪 silver shellfish.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body provides focused test/check output but explicitly says live Dev Gateway, real agent, and managed Chromium dynamic-page proof is still pending, so real behavior proof is not yet sufficient before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P2: This is a normal-priority Browser reliability fix with a bounded upload-hook correctness blocker and no evidence of a core outage.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦪 silver shellfish and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body provides focused test/check output but explicitly says live Dev Gateway, real agent, and managed Chromium dynamic-page proof is still pending, so real behavior proof is not yet sufficient before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source -1, Tests +71, Docs +2. Total +72 across 6 files.

View PR surface stats
Area Files Added Removed Net
Source 2 11 12 -1
Tests 2 71 0 +71
Docs 2 3 1 +2
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 6 85 13 +72

What I checked:

Likely related people:

  • steipete: Authored the Browser ownership move and browser plugin runtime packaging commits that made the current bundled Browser plugin surface the owner of these files. (role: recent area contributor; confidence: high; commits: 8eeb7f082975, 197510f69302; files: extensions/browser/src/browser/client-actions-core.ts, extensions/browser/src/browser/routes/agent.act.hooks.ts, extensions/browser/src/browser-tool.ts)
  • joshavant: Authored the Browser /act route consolidation commit adjacent to action validation and contract-error behavior that the upload trigger click relies on. (role: adjacent route refactor contributor; confidence: medium; commits: f096fc440686; files: extensions/browser/src/browser/routes/agent.act.hooks.ts, extensions/browser/src/browser/pw-tools-core.interactions.ts)
  • vincentkoc: Recent history shows adjacent Browser CLI/runtime seam work and release/current-main activity near the Browser area, useful for routing but less directly tied to file chooser hooks. (role: recent adjacent contributor; confidence: low; commits: 0e54440ecc39, e085fa1a3ffd; files: extensions/browser/src/browser/client-actions-core.ts, extensions/browser/src/browser-tool.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 7, 2026
@steipete
steipete force-pushed the codex/browser-upload-file-chooser branch from 6a48a70 to b16eb37 Compare July 7, 2026 11:24

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b16eb378cd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

timeoutMs: opts.timeoutMs,
}),
timeoutMs: 20000,
timeoutMs: resolveBrowserOperationRequestTimeoutMs(opts.timeoutMs),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pass upload timeouts through direct-input uploads

When action=upload uses inputRef or element with a short explicit timeoutMs, this new watchdog becomes timeoutMs + 5000, but the route does not pass that timeout into direct file-input uploads (extensions/browser/src/browser/routes/agent.act.hooks.ts:96-102), and setInputFilesViaPlaywright calls locator.setInputFiles(resolvedPaths) without options (extensions/browser/src/browser/pw-tools-core.interactions.ts:1495-1496). A slow/stale input can therefore still be cut off by the client first and return the generic browser-control timeout this change is trying to avoid. Either forward the timeout to setInputFiles or keep the outer watchdog above the direct-input operation timeout.

Useful? React with 👍 / 👎.

@steipete

steipete commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Land-ready proof for exact head b16eb378cdd46f09bebee12349a947a9f9fe6a5d.

What this solves:

  • A file chooser has to be armed before the click that creates it. The recommended paths + ref form now makes that ordering atomic in one browser operation, while direct input upload and the existing paths-only arm-then-click mode remain supported.
  • Hook requests previously had the same outer HTTP timeout as the inner browser operation. The outer client could therefore abort first and replace a useful Playwright error with Can't reach the OpenClaw browser control service. The request now gets a fixed five-second transport margin while the browser operation remains the authoritative timeout.

Dependency contract checked directly against the installed [email protected] package: types/types.d.ts:19248-19258 says to start page.waitForEvent('filechooser') before clicking; types/types.d.ts:4878 exposes the event timeout; types/types.d.ts:19277-19327 defines FileChooser.setFiles and its timeout.

Verification:

  • Focused Blacksmith Testbox run: 92/92 tests passed across extensions/browser/src/browser-tool.test.ts, extensions/browser/src/browser/client-actions-core.hooks.test.ts, extensions/browser/src/browser/pw-tools-core.last-file-chooser-arm-wins.test.ts, and extensions/browser/src/browser/pw-tools-core.upload-paths.test.ts.
  • Exact-head pnpm check:changed: passed in 2m20.964s on Testbox tbx_01kwy411jwmgvgk97n62fwjd15.
  • Live proof: AWS Crabbox cbx_d9f1ede1c74e, run run_c7e9c1042153, with a real Gateway, managed Chromium, and openai/gpt-5.4. The agent atomically uploaded atomic-upload-38844.txt and the page received its content marker. After rerendering the trigger, reuse of the stale ref returned specific re-snapshot guidance and did not contain the generic browser-service reachability error. A separate paths-only arm followed by a later click also uploaded successfully.
  • Fresh autoreview: no actionable findings.

The refactor is bounded: five files, +84/-13 overall, and production code is net -1 line. No filesystem allowlist, sandbox permission, or browser networking boundary changed.

@steipete
steipete merged commit bd7da9d into main Jul 7, 2026
96 checks passed
@steipete
steipete deleted the codex/browser-upload-file-chooser branch July 7, 2026 11:35
@steipete

steipete commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Merged via squash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to documentation maintainer Maintainer-authored PR P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: browser upload/file chooser flow is flaky and can misreport stale-click failures as browser control timeouts

1 participant