Skip to content

[Bug]: Claude Desktop picker mode breaks claude.ai chat (sends time out, picker 502s) since the merged chat/Cowork front end; picker off fixes it #6511

Closed

Description

@rhomat27

Client or integration

Claude Desktop (macOS), first-party mode with picker mode on

Area

Proxy / Claude Desktop picker (claude-intercept egress on 127.0.0.1:10201)

Summary

With picker mode active, Claude Desktop pins all of its traffic to the opencodex egress proxy ([egress-proxy] pinned to fixed proxy at 127.0.0.1:10201; OS proxy settings ignored). Since 2026-10-02 ~12:00 local, the chat side of Desktop no longer works: a sent message spins and eventually fails with "message could not be sent", and sessions fail with "Timed out loading session". The Code tab keeps working, and opencodex models still appear in the Code tab picker.

The breakage lines up with a new claude.ai front-end build loading in Desktop (the merged chat/Cowork experience, served remotely, so no app update was needed). The first failed send was 16 minutes after that build first loaded. Picker mode had worked with chat since 2026-09-26.

Turning the picker off (ocx claude desktop picker off, restart Desktop) removes the egress pin, and chat works with zero errors. Turning it back on brings the failures back. Upgrading 2.72.0 → 2.76.0 did not fix it.

Reproduction

  1. macOS, opencodex in first-party mode with ocx claude desktop picker on (status: effective: true, reason: active, trust: trusted).
  2. Claude Desktop 2.19675.0, on an account that has the merged chat/Cowork front end.
  3. Open the chat side (not the Code tab) and send any message.
  4. The message spins, then "message could not be sent". Existing chats fail to load with "Timed out loading session. Check your connection and try again."
  5. Run ocx claude desktop picker off, quit and reopen Desktop. Chat works.

Version

  • opencodex 2.72.0 (when it started), still reproduces on 2.76.0
  • Claude Desktop 2.19675.0, bundled Claude Code 2.1.286

Operating system

macOS 26.6.2 (25G83), arm64

Provider and model

Not model-specific. The failing traffic is Desktop's own claude.ai traffic (chat UI, session loads, feature flags), not routed model requests.

Logs or error output

Desktop claude.ai-web.log (renderer), starting 2026-10-02:

12:16:15 [error] [useSendChannelMessage] send failed [object DOMException]
12:16:57 [warn] [REACT_QUERY_CLIENT] QueryClient error: {"name":"TimeoutError","message":"Timed out loading session. Check your connection and try again."}

Desktop main.log: main-process fetches to claude.ai time out continuously while the picker is active (349 on 10-02, 517 on 10-03 so far):

[warn] [my-access] fetch failed { error: DOMException [TimeoutError]: The operation was aborted due to timeout }
[error] [growthbook] network error: DOMException [TimeoutError]
[error] Failed to check allowlist status: DOMException [TimeoutError]
[warn] [RemotePluginManager] Failed to fetch enabled state; defaulting to all-enabled This operation was aborted

opencodex stdout during the same window: the picker answers some claude.ai requests with 502 (2.72.0: 590 GET + 368 POST 502s in the log; 2.76.0 since this morning: 15 GET + 3 POST 502s):

[claude-picker] picker GET other 502
[claude-picker] picker POST other 502

Timeline (local time):

  • 2026-09-26: picker mode applied. Chat works through the egress proxy.
  • 2026-10-02 ~12:00: new claude.ai web build (asset c219730b0) first loads in Desktop.
  • 2026-10-02 12:16: first failed send. Failures continue all day.
  • 2026-10-02 22:16: Desktop restarted with the picker off: zero timeouts or failed sends afterwards.
  • 2026-10-03 00:13: opencodex auto-updated to 2.76.0, picker back on. Failures resume (latest 08:55 on 10-03).

Plain curl -x http://127.0.0.1:10201 https://claude.ai/ returns quickly with the same status as a direct request, so the listener is up. The failures look specific to the requests the new front end makes.

Redacted configuration

"claudeCode": { "enabled": true, "desktopMode": "first-party", "desktopNativeModels": true, "intercept": { "picker": true } }

Desktop applied profile (Claude-3p/configLibrary, "opencodex-picker"): {"egressProxyUrl":"http://127.0.0.1:10201"}

Checks

Activity

  1. Ingwannu commented on Oct 4, 2026

    @Ingwannu
    Owner

    Related #6551 now has independently reproduced offline listener evidence: at 76fcad4 the 14 local TLS tests pass, including 24 KiB cookies, binary/SSE streaming and bounded overflow responses. This establishes the parser/header compatibility correction, not that it caused your merged-chat/Cowork failure: no captured Desktop header-size evidence or native macOS acceptance was collected here. Please keep this issue open pending that correlation. A useful redacted follow-up is exact OpenCodex/Desktop versions and whether the same send/session-loading failure recurs after the fix is available; do not post cookies, authorization headers, bodies or account data. I have not toggled the picker or restarted a live Desktop session.

  2. lidge-jun commented on Oct 4, 2026

    @lidge-jun
    Owner

    The bounded picker-header correction has landed on dev via #6551, commit df3dd3f. Large ordinary request/response session headers are allowed up to the explicit limit; overflow, body/cookie preservation, streaming, upgrades and TLS behavior have focused and hosted regression evidence.

    Keeping this issue open: the synthetic parser reproduction does not establish that header size caused the reported merged-chat/Cowork failure in the actual Desktop app. Native symptom correlation and end-to-end acceptance on the affected client remain outstanding. No installed profile, keychain trust or network setup was modified by this integration.

  3. rhomat27 commented on Oct 4, 2026

    @rhomat27
    ContributorAuthor

    Tested the #6551 fix on the affected machine. It removes the 502s, but chat still does not load.

    Setup

    • opencodex 2.76.0 with only the src/claude/intercept/picker-listener.ts change from df3dd3f applied (the PICKER_MAX_HEADER_BYTES server and upstream limits plus the overflow log). Nothing else changed.
    • Restarted opencodex at 08:57 CDT (healthy), turned the picker on, then fully quit and reopened Claude Desktop 2.19675.0 at 09:01:42 CDT. Desktop logged [egress-proxy] pinned to fixed proxy at 127.0.0.1:10201.
    • macOS 26.6.2, arm64.

    What changed

    • No picker 502s since the restart (60 completed picker requests: 200/202/204/302/304 only). Before the patch the same log had 15 GET + 3 POST 502s.
    • upstream:headers-too-large was never logged.

    What did not change

    • The chat side never finishes loading. Within 3 minutes the renderer logged Timed out loading session. Check your connection and try again. 6 times and signal timed out 5 times.
    • Main-process fetches to claude.ai still time out: Failed to check allowlist status, Failed to fetch blocklist, Failed to check can_install, [growthbook] network error, [RemotePluginManager] Failed to fetch enabled state ... aborted, [SkillsPlugin] Skills request timed out.

    Observations that may help

    • The requests hang. They don't fail: only 60 picker requests completed in the first ~7 minutes, while 52 client connections into 10201 and about 50 upstream connections to Anthropic's edge stayed open.
    • The picker log has 83 GET other 101 (WebSocket upgrade) lines in total, and that count has not changed since at least Oct 2 evening, when chat was already broken. Nothing has upgraded since this restart either. The renderer's failing call is [useSendChannelMessage] send failed, so the new front end may depend on a long-lived channel that doesn't make it through the relay. This is an inference from the logs; I have no packet capture.
    • With the picker off (no egress pin), the same Desktop build loads and sends with zero timeouts.

    I'm leaving the picker off for daily use and can re-test a build on request.

  4. Ingwannu commented on Oct 4, 2026

    @Ingwannu
    Owner

    This separates the two symptoms: your single-patch retest removes the picker 502s, but the send/session-loading failure remains and disappears with the picker off. #6551 is therefore not end-to-end resolution of this issue; it stays open.

    One detail from current dev a6bc608: the ordinary picker METHOD other STATUS line is emitted when response headers are written, not when the response body finishes. Those 60 lines and the open-socket count cannot by themselves distinguish a normal long-lived stream from a request stuck waiting for upstream headers. Likewise, an unchanged historical 101 count does not yet prove the failing request uses WebSocket.

    If you can safely provide one representative failed session-load request from existing Network/diagnostic information, please include only: method and pathname (remove query/fragment and redact IDs), whether HTTP response headers arrived before timeout, and whether an Upgrade was requested/accepted (yes/no and status only). A response content type, if available, would distinguish SSE from ordinary HTTP. No full HAR, cookies, authorization headers, bodies, account data, packet capture or repeated daily picker toggling is needed. I have not reproduced the actual macOS client or established a relay fix, and have not changed any live profile/service.

  5. rhomat27 commented on Oct 4, 2026

    @rhomat27
    ContributorAuthor

    Captured with temporary local logging in the picker listener and the CONNECT proxy. The logs recorded method, redacted path, whether headers arrived and the content type. No query strings, headers, cookies or bodies were logged. Run: Claude Desktop 2.19675.0 started 13:28:25 CDT with the picker on, opencodex 2.76.0 plus the #6551 header change, observed for about 4 minutes.

    Every request that reached the picker got headers back. 80 requests started, 80 received response headers (all 2xx), and none hit a 15-second no-headers timer. No Upgrade was requested or accepted; the upgrade handler never fired.

    The long-lived requests are SSE streams that stay open:

    • GET /v1/code/channels/:id/messages/stream: 200, text/event-stream, headers in about 210–300 ms. Six of these opened in the first minute and none closed.
    • The ordinary JSON calls completed normally: /v1/code/sessions, /v1/code/sessions/:id, /v1/code/channels/:id/timeline, /v1/code/sessions/:id/events, /api/organizations/....

    The requests that time out never reach the picker. Over the same window Desktop logged main-process timeouts ([growthbook] network error, Failed to check can_install, [my-access] fetch failed, [RemotePluginManager] ... aborted) and renderer signal timed out errors. The picker log has no start line for any of them. Only 9 CONNECT claude.ai:443 tunnels were opened in total.

    Likely cause: the picker listener only offers http/1.1 (ALPNProtocols: ["http/1.1"]), so each open SSE stream holds a whole connection. Chromium allows 6 HTTP/1.1 connections per host, so once the merged front end has 6 messages/stream subscriptions open, every other claude.ai request from the same Electron session waits for a free connection and times out. A direct connection to claude.ai negotiates HTTP/2, where those streams share one connection, which matches the picker-off case working. It also explains why the fault appeared when the new front end started opening per-channel streams, not after an opencodex change.

    If that holds, the fix is HTTP/2 on the picker's client-facing side (ALPN h2 with an h2-capable relay), or otherwise keeping Desktop from multiplexing claude.ai streams over HTTP/1.1. The picker is off again on this machine and the temporary logging has been removed.

  6. rhomat27 commented on Oct 4, 2026

    @rhomat27
    ContributorAuthor

    Answers to the four questions, plus a same-session re-test. All times are CDT on Oct 4. No query strings, IDs, headers, cookies or bodies are included.

    A failed session-load request, in the fields you asked for

    • The requests that time out (Timed out loading session, signal timed out, and main-process growthbook / can_install / my-access / RemotePluginManager) never reached the picker listener. With per-request logging on, none of them produced a start line, so I have no method or pathname for them from the relay side.
    • Response headers: not applicable, because the request never arrived. Every request that did reach the listener (80 of 80) got headers back, and none went past a 15-second no-headers timer.
    • Upgrade: none requested and none accepted. The upgrade handler never fired.
    • Content type: the only long-lived responses were GET /v1/code/channels/:id/messages/stream, 200 text/event-stream, with headers in about 210–300 ms. Six opened in the first minute and none closed.

    Same-session re-test (Desktop 2.19675.0 started 13:28, not restarted afterwards)

    1. 13:28–13:30, picker on: the six SSE streams open, then the timeouts above begin.
    2. 13:30, picker turned off and opencodex restarted. Desktop stayed pinned to 127.0.0.1:10201, and new claude.ai CONNECTs were blind-tunnelled. Chat recovered and a Sonnet message sent. The picker logged nothing for that send.
    3. 13:33, picker turned back on with no Desktop restart. Chat kept working while Desktop reused the blind tunnels.
    4. From 13:37, Desktop opened new connections (established connections to 10201 rose from 10 to 46). Those were intercepted, and the timeouts resumed at 13:38:36. The picker logged 2 requests between 13:37:53 and 13:40:32.
    5. 13:40, picker off again.

    In one app process, chat works while claude.ai reaches Anthropic through a blind tunnel and jams once its connections terminate at the HTTP/1.1-only picker listener. That matches the per-host connection limit described in my previous comment.

  7. Ingwannu commented on Oct 4, 2026

    @Ingwannu
    Owner

    Your two follow-ups answer the diagnostic questions; no further picker toggling or full HAR is needed. The important new distinction is that the timed-out requests never enter the listener, while every observed request receives headers and the long-lived responses are SSE, not upgrades.

    At current dev 69ce37c24e, picker-listener.ts still advertises only http/1.1 on the client-facing TLS connection. Ordinary non-bootstrap responses are piped through without collecting their bodies. Your same-process blind-tunnel/intercept A/B therefore supports a client-side connection-slot starvation hypothesis; it is not evidence that another header-limit increase fixes the remaining problem. The exact pool limit and negotiated direct protocol have not been independently established here.

    The next useful regression is a client with a bounded HTTP/1.1 connection pool holding the long-lived SSE subscriptions, then an ordinary request to the same origin. It must exercise queueing before listener entry; an unrestricted raw-client test opening extra sockets would miss that behavior. Any multiplexing fix needs actual negotiated-protocol and concurrent-stream evidence, plus cancellation/streaming and bootstrap rewriting coverage—not merely advertising h2 to the existing HTTP/1.1 parser.

    Keeping #6511 open. #6551's header correction remains a separate scoped result, not end-to-end resolution. I have not run the native macOS client or changed a live profile/service.

  8. lidge-jun commented on Oct 5, 2026

    @lidge-jun
    Owner

    Thanks for the detailed captures; they pinned this down. Your relay logs showed six messages/stream SSE responses staying open while the timed-out requests never reached the picker. Both point to the same cause: the picker listener only offered HTTP/1.1, so each open stream held one of Chromium's six connections to claude.ai and later requests queued inside Desktop. #6610 (merged to dev as aa10846a4c) makes the picker serve HTTP/2, so Desktop multiplexes all claude.ai requests over one connection, as it does when it talks to Anthropic directly. WebSocket connections and clients without HTTP/2 stay on the existing HTTP/1.1 path.

    If you can retest:

    1. Run a build that includes aa10846a4c: the next release, or dev at or after that commit. Restart OpenCodex, turn picker mode on, then fully quit and reopen Claude Desktop.
    2. In the OpenCodex log (ocx status shows its path), look for lines starting with [claude-picker]. Soon after Desktop starts you should see [claude-picker] picker session h2, which confirms Desktop negotiated HTTP/2 with the picker. Normal [claude-picker] picker GET other 200 lines should follow.
    3. Check whether chat loads and a message sends, and whether "Timed out loading session" or signal timed out comes back over a few minutes.

    A short redacted reply is enough: OpenCodex and Desktop versions, whether picker session h2 appeared, whether chat loaded and sent, and any picker request refused lines (a new guard; there shouldn't be any). Please don't include cookies, headers, bodies or account data. If chat still stalls, ocx claude desktop picker off brings it back right away, as before.

  9. rhomat27 commented on Oct 5, 2026

    @rhomat27
    ContributorAuthor

    Retested on v2.78.0-preview.20261005, which includes aa10846a4c. I ran the release source on the laptop. The Mini is unchanged.

    • Versions: OpenCodex 2.78.0-preview.20261005, Claude Desktop 2.19675.0, macOS.
    • Setup: I restarted OpenCodex with picker mode on, then fully quit and reopened Desktop.
    • [claude-picker] picker session h2: yes, 2 sessions since the restart.
    • picker request refused: none.
    • Picker requests since the restart:
      • GET: 304 × 200, 24 × 304, 1 × 302
      • POST: 115 × 200, 37 × 202, 1 × 404
      • PATCH: 1 × 200, 3 × 400
      • No 502s, where the HTTP/1.1 runs before this had several hundred.
    • Chat: loads and sends, with no "Timed out loading session" and no signal timed out.
    • Code picker: the routed models are listed. A routed model also works when selected in a new thread.

    This is fixed for us. Thanks for turning it around so fast.

  10. lidge-jun commented on Oct 5, 2026

    @lidge-jun
    Owner

    Fixed by #6610 (aa10846, in 2.78.0-preview.20261005): the picker now serves HTTP/2, so Claude Desktop multiplexes claude.ai requests over one connection instead of exhausting Chromium's six HTTP/1.1 slots. Thank you for the captures and for confirming on the preview that HTTP/2 negotiated, chat loads and sends, and the 502s and timeouts are gone. If anything regresses, ocx claude desktop picker off restores the blind tunnel immediately; please reopen with the redacted log lines.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions