Skip to content

fix: extend daemon proxy read timeout - #1885

Closed
buiilding wants to merge 1 commit into
trycua:mainfrom
buiilding:codex/fix-daemon-proxy-timeout
Closed

fix: extend daemon proxy read timeout#1885
buiilding wants to merge 1 commit into
trycua:mainfrom
buiilding:codex/fix-daemon-proxy-timeout

Conversation

@buiilding

@buiilding buiilding commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #1864.

This PR fixes the MCP -> daemon proxy timeout described in the issue. It does not make get_window_state smaller or bypass AX traversal; it makes the daemon transport wait long enough for legitimate tool execution and return a clearer transport timeout if the daemon still does not respond.

Issue Behavior Addressed

The issue reports that this path can fail:

MCP client -> cua-driver mcp stdio server -> cua-driver serve daemon over Unix socket -> get_window_state

The same get_window_state operation can look healthy through cua-driver call, while the MCP proxy path fails with:

Resource temporarily unavailable (os error 35)

The root cause fixed here is the proxy client read timeout: send_request used a hardcoded 10-second socket read timeout. Slow but valid daemon calls, especially get_window_state, could exceed that transport timeout before the tool returned its own result or timeout. On macOS, that timed-out socket read appears as WouldBlock / EAGAIN / os error 35.

What Changed

  • Replaced the inline daemon socket timeout with named daemon write/read timeout constants.
  • Raised the daemon read timeout from 10 seconds to 60 seconds.
  • Kept the write timeout short at 5 seconds.
  • Mapped WouldBlock / TimedOut while reading the daemon response into a clear error:
daemon timed out waiting for response after 60s

The 60-second transport budget is intentionally above the macOS get_window_state AX walk timeout of 30 seconds, leaving room for screenshot capture, resizing/encoding or screenshot_out_file, and JSON response serialization.

This PR intentionally does not blindly retry on EAGAIN. In this code path, EAGAIN is the socket read timeout firing, not a transient readiness event from a nonblocking socket loop. Retrying would hide the timeout policy instead of fixing the proxy deadline.

Relation To The Issue's Upstream Questions

Resolved by this PR:

  • os error 35 / EAGAIN in the MCP -> daemon proxy no longer leaks as the primary failure for slow-but-valid daemon responses below the transport budget.
  • The proxy now waits longer than the old 10-second transport timeout and longer than the macOS get_window_state AX timeout.
  • If the daemon still does not respond inside the transport budget, the user gets a daemon timeout message instead of raw macOS EAGAIN.

Not changed by this PR and still follow-up scope:

  • Whether screenshot_out_file should be the recommended long-term payload-size strategy.
  • Whether large screenshot payloads should default to files or be chunked.
  • Whether Apple Notes empty/unusable AX trees are a known platform limitation or need an alternate traversal path.
  • Coordinate click semantics on HiDPI displays, including whether coordinate click should accept window_id for multi-window disambiguation.
  • Idle CPU around 52-54% in the driver process.
  • Whether the removed screenshot tool is intentionally replaced by get_window_state(capture_mode=vision).

screenshot_out_file remains useful as an optional payload-size mitigation, but it is not the primary fix for this bug. The transport timeout/backpressure behavior is the bug addressed here.

Validation

  • cargo test -p cua-driver daemon_response_read_tests
  • git diff --check
  • local install-local.sh rebuild and CuaDriver daemon restart
  • forced MCP proxy reproduction with a fake daemon delaying get_window_state for 12 seconds; the call succeeds instead of failing at the old ~10-second transport timeout

The MCP stdio proxy forwarded tool calls to the daemon over a Unix socket with a 10-second read timeout. Slow get_window_state calls could exceed that transport budget before the tool-level timeout fired, causing macOS EAGAIN/os error 35 to surface as a daemon transport failure.\n\nThis change gives the daemon proxy a 60-second read timeout, keeps the existing short write timeout, and normalizes WouldBlock/TimedOut into a clear daemon timeout error. It also adds focused tests for response-line handling and timeout mapping.\n\nBefore this change, a delayed daemon response reproduced the issue by failing around 10 seconds. After this change, a 12-second delayed MCP proxy call succeeds while still bounding truly stuck daemon reads.
@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

@buiilding is attempting to deploy a commit to the Cua Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6f307e94-b61d-492a-b025-abd5d7d3d86d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@injaneity

Copy link
Copy Markdown
Collaborator

closed as superseded by #1997

@injaneity injaneity closed this Jul 20, 2026
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.

cua-driver MCP daemon proxy returns os error 35 forwarding get_window_state

2 participants