← Back to PRs

#17946: fix(browser): prevent act timeout on Linux by removing premature abort trigger

by rteece111 open 2026-02-16 10:06 View on GitHub →
stale size: XS
## Summary Fixes browser `act` timeout on Linux for click/type/fill operations by removing premature abort trigger in Express middleware. Resolves #11691 ## Problem Browser `act` operations (click, type, fill) timeout on Linux while working correctly on macOS. Other browser actions (navigate, snapshot, screenshot) work fine on both platforms. **Symptoms:** - Click/type/fill timeout after 30 seconds on Linux - Playwright logs show: "element is visible, enabled and stable" → "retrying click action" → timeout - Same operations work on macOS without issues ## Root Cause Commit `424d2ddf` (v2026.2.12) added AbortSignal handling to prevent stuck evaluate operations. The middleware in `src/browser/server-middleware.ts` creates an AbortController for every HTTP request and aborts on `res.close`: ```typescript res.once("close", () => { if (!res.writableEnded) { abort(); } }); ``` **The bug:** On Linux, Express fires the `res.close` event **before** `writableEnded` is set during long-running Playwright operations. This causes: 1. Premature `ctrl.abort()` trigger mid-operation 2. Abort signal propagates to `forceDisconnectPlaywrightForTarget()` 3. Playwright connection forcibly disconnected during click/type/fill 4. Operation fails with timeout macOS handles `res.close` differently and doesn't exhibit this behavior. ## Fix Removed the `res.close` abort trigger from the middleware. The abort protection is now scoped only to the `req.aborted` event, which reliably detects actual client disconnections across platforms. **File changed:** `src/browser/server-middleware.ts` **Lines changed:** 7 insertions(+), 5 deletions(-) ## Testing Tested on **Ubuntu 24.04** EC2 instance with TrackMyTrades login form: ✅ **Click** "Log In" button → completed successfully ✅ **Type** email field → completed successfully ✅ **Type** password field → completed successfully ✅ **Click** "Login" button → completed successfully ✅ Successfully logged into application All operations completed without timeout. Browser profile: `openclaw` (Brave headless). ## Rationale 1. **Minimal change:** Removes only the problematic `res.close` handler 2. **Platform-agnostic:** Relies on `req.aborted` which works consistently on Linux and macOS 3. **Preserves abort protection:** Still catches actual client disconnections 4. **Non-breaking:** Restores pre-v2026.2.12 behavior for click/type/fill while keeping other improvements ## Checklist - [x] Root cause identified via git bisect - [x] Fix tested on Linux (Ubuntu 24.04) - [x] No regression on macOS expected (relies on standard Express events) - [x] Minimal code change (7 lines) - [x] Related issue referenced (#11691) <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes browser `act` timeouts (click/type/fill) on Linux by removing the `res.close` abort handler from the Express middleware in `src/browser/server-middleware.ts`. The `res.close` event was firing prematurely on Linux during long-running Playwright operations, causing the `AbortController` to abort mid-operation. - **Potential issue**: The remaining `req.once("aborted", ...)` listener relies on a **deprecated** Node.js API ([DEP0133](https://nodejs.org/api/deprecations.html#DEP0133), since v16.12.0). With the project requiring `node >= 22.12.0`, this event may not fire reliably and could silently leave the abort signal inert on client disconnections. A safer cross-platform approach would be `req.once("close", () => { if (req.destroyed) abort(); })`. - The abort signal is currently only consumed by `evaluateViaPlaywright` (via `req.signal` in `agent.act.ts:321`), not by click/type/fill operations, so the functional impact of this change is limited to evaluate abort protection. - Commented-out code should be deleted in favor of relying on version control history. <h3>Confidence Score: 2/5</h3> - The fix addresses the Linux timeout but introduces a reliance on a deprecated Node.js API that may silently fail. - Score of 2 reflects that while the PR correctly identifies and removes the problematic `res.close` handler, the remaining abort mechanism (`req.once("aborted", ...)`) uses deprecated Node.js API DEP0133. On the project's required Node.js >=22.12.0, this event may not fire, meaning client disconnection detection could silently stop working. The correct fix should use `req.once("close", ...)` with `req.destroyed` instead. - `src/browser/server-middleware.ts` — the abort listener uses a deprecated event that should be replaced with the modern `req.close` + `req.destroyed` pattern. <sub>Last reviewed commit: ae036de</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs