[BUG] Remote Control SSE channel (worker/events/stream) ignores NODE_EXTRA_CA_CERTS while the API channel honors it — same process, v2.1.201 (it's Node, not Bun)

Open 💬 0 comments Opened Jul 7, 2026 by fgrosswig

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The regular API path (chat) validates fine through the proxy, but the Remote-Control SSE transport loops forever on a self-signed-cert error. Both run in the same process, both go through the same proxy, both should use the same CA material — but only the API path picks up the configured extra CA.

What Should Happen?

The SSE fetch() should trust the same CA material as the API client. A user who sets NODE_EXTRA_CA_CERTS (exactly as the client's own error message instructs) should get a working Remote Control SSE channel. API-channel and SSE-channel TLS trust must be identical within the same process.

Error Messages/Logs

SSETransport: Opening https://api.anthropic.com/v1/code/sessions/<id>/worker/events/stream
SSETransport: Connection error: self signed certificate in certificate chain
SSETransport: Reconnecting in 30588ms (attempt 35, 885s elapsed)
[remote-bridge] Sending 1 message(s)          <- outbound still works

Steps to Reproduce

  1. Put the client behind a TLS-inspecting proxy (Zscaler/Netskope/self-hosted) that re-signs api.anthropic.com with an internal Root CA installed in the OS store.
  2. Confirm the API path works — normal chat/completions succeed through the proxy.
  3. Enable Remote Control → the SSE channel loops on self signed certificate in certificate chain.
  4. Set NODE_EXTRA_CA_CERTS to a PEM containing the Root CA (verify with openssl verify), fully restart the client. Confirm it is in the process env (echo $NODE_EXTRA_CA_CERTS). API keeps working, SSE keeps failing.

Claude Model

None

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

2.1.201

Platform

Other

Operating System

Windows

Terminal/Shell

VS Code integrated terminal

Additional Information

It's Node, not Bun — binary evidence

Previous corporate-proxy issues were dismissed on the assumption of an unfixable "Bun isolated networking stack." The binary is Node.js, verified by string/symbol analysis of the native SEA:

  • setGlobalDispatcher (undici), setDefaultCACertificates, getCACertificates — all Node APIs.
  • CA material comes from a single getCACertificates(type = "default") call (not "system"; the --use-system-ca string exists but isn't used here).
  • The SSE transport uses a bare fetch() with no dispatcher / agent / ca:
// SSETransport.open()
let o = await fetch(t.href, { headers: r, signal: this.abortController.signal });
// grep for `dispatcher:` in any fetch option across the whole binary → 0 hits
  • The binary even ships the error string advising "set NODE_EXTRA_CA_CERTS to your CA bundle path" — which does not fix the SSE path.

win32-x64 vs linux-x64 — identical code, only runtime differs

Same greps against both binaries of release 2.1.201:

| Probe | win32-x64 | linux-x64 |
|---|---|---|
| getCACertificates(type) | "default" | "default" |
| use-system-ca / "system" / "bundled" / "extra" | 8 / 490 / 37 / 2 | 8 / 490 / 37 / 2 |
| setGlobalDispatcher / setDefaultCACertificates | 4 / 2 | 4 / 2 |
| SSETransport | bare fetch() | bare fetch() |
| dispatcher: in fetch opts | none | none |

The Linux client's SSE works only because NODE_EXTRA_CA_CERTS is in the OS env at bootstrap (login shell), so it lands in the getCACertificates("default") snapshot before any TLS context is built. On Windows the SSE path does not pick it up even when the variable is in the process env.

Likely cause (for maintainers to confirm)

The global undici dispatcher is constructed from a CA snapshot taken before the extra CA is applied, or the SSE fetch bypasses the dispatcher that carries the extra CA (the API/SDK path uses an explicit httpsAgent/ca; the SSE path uses bare global fetch). Either way: API-channel TLS trust ≠ SSE-channel TLS trust, in the same process.

Suggested fixes

  1. Route the SSE fetch() through the same dispatcher/Agent as the API client (built with the resolved CA including the "extra" set).
  2. (Re)apply setDefaultCACertificates(getCACertificates("default")) before the SSE transport initializes, and re-read NODE_EXTRA_CA_CERTS when constructing the SSE dispatcher — so late-injected env (VS Code settings, Windows user env) is honored, matching the API path.
  3. Optionally honor --use-system-ca / the OS trust store for the SSE path.
  4. Re-enable a diagnostic surface — NODE_DEBUG=tls is dead in the SEA build.

Related issues — same class, all dismissed

Why this is not a duplicate: those report the general "NODE_EXTRA_CA_CERTS ignored" symptom and were dismissed (several assuming an unfixable "Bun" stack). This report adds (a) the same-process API-vs-SSE divergence with the variable proven present, (b) binary evidence the runtime is Node, not Bun, and (c) it reproduces on the current 2.1.201 — a live, addressable Node code-path defect, not an inherent runtime limitation.

Workaround

Exempt api.anthropic.com from TLS inspection for the client IP (don't rewrite it to the MITM gateway). The SSE channel then validates against the genuine Anthropic leaf via the bundled Mozilla roots.

View original on GitHub ↗