Voice mode fails with 'Voice connection failed' — Cloudflare challenge blocks WebSocket to claude.ai
Environment
- OS: Windows 10/11 (x64)
- Node.js: v20.18.1
- Claude Code: 2.1.76
- Auth: claude.ai OAuth, subscription: max
- Region: Romania (Bucharest), ISP: DIGI ROMANIA S.A. (AS8708)
Bug Description
/voice enables successfully ("Voice mode enabled. Hold Space to record."), but after recording and releasing Space, it always fails with:
Voice connection failed. Check your network and try again.
Root Cause Analysis
The voice stream WebSocket (wss://claude.ai/api/ws/speech_to_text/voice_stream) never connects because Cloudflare blocks all programmatic requests to claude.ai from this IP/region with a JavaScript challenge.
Any HTTP request to claude.ai returns:
HTTP 403
cf-mitigated: challenge
server: cloudflare
This challenge cannot be solved by a CLI/Node.js WebSocket client, so the connection never establishes. The finishRecording() function sees wsConnected=false and transcriptChars=0, triggering the "Voice connection failed" error.
What Works
| Component | Status |
|-----------|--------|
| Native audio module (audio-capture.node x64-win32) | Loads OK, 7 exports |
| OAuth authentication | loggedIn: true |
| api.anthropic.com (main API) | Works fine (no Cloudflare challenge) |
| Microphone / audio devices | 4 devices, all status OK |
| Windows Firewall | Claude rules: Allow in/out |
| DNS resolution for claude.ai | Resolves to 160.79.104.10 |
| TLS to claude.ai | TLSv1.3, certificate valid |
What Fails
- ANY programmatic request from Node.js to
claude.ai→ 403 withcf-mitigated: challenge - WebSocket upgrade to
wss://claude.ai/...→ blocked by Cloudflare before reaching server
Reproduction
# This returns 403 with cf-mitigated: challenge
curl -s -o /dev/null -w "%{http_code}" https://claude.ai
# Returns: 403
# This works fine
curl -s -o /dev/null -w "%{http_code}" https://api.anthropic.com
# Returns: 404 (expected, no auth)
Expected Behavior
Voice WebSocket should connect to claude.ai without being blocked by Cloudflare challenge, similar to how api.anthropic.com handles CLI connections.
Workaround
Using a VPN changes the IP and bypasses the Cloudflare challenge, making voice mode work. This confirms the issue is IP/region-based Cloudflare challenge policy.
Suggested Fix
Consider one of:
- Exempting the
/api/ws/speech_to_text/voice_streamendpoint from Cloudflare JavaScript challenges (requests include valid OAuth Bearer tokens) - Using a separate non-challenge-protected domain for the voice stream (similar to
api.anthropic.com) - Adding a Cloudflare bypass token/header for authenticated CLI clients
6 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Additional confirmation — Windows 11, native binary, VPN tested
Environment:
claude.exe, NOT npm)Same symptoms: Recording indicator appears, push-to-talk works, but no transcription on release — silent failure (no error message displayed, unlike the OP who gets "Voice connection failed").
Additional finding — VPN does NOT help:
Tested with ExpressVPN (US Houston, TX). The Cloudflare challenge persists because it's triggered by the User-Agent (Node.js/WebSocket), not the IP address:
This confirms the Cloudflare challenge is UA-based, not IP/region-based. A VPN is not a viable workaround.
Workaround: Using VoiceMode MCP with local Whisper STT instead of native
/voice.Seeing the same thing from a Thailand local ISP's fiberoptic connection here — Curling
https://claude.aibeing blocked with 403 and the voice mode itself failing with "Check your connection". Rest of Claude Code seems to work fine fortunately except voice mode.The issue is people are letting go of the spacebar instead of holding it.
This was fixed in v2.1.80 — Voice mode now connects via api.anthropic.com instead of claude.ai, avoiding Cloudflare bot-challenge failures on the WebSocket. If you're still seeing this in the latest version, please comment with your version and repro and we'll reopen.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.