Voice mode fails with 'Voice connection failed' — Cloudflare challenge blocks WebSocket to claude.ai

Resolved 💬 6 comments Opened Mar 14, 2026 by DmitriyChumak Closed Apr 18, 2026

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 with cf-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:

  1. Exempting the /api/ws/speech_to_text/voice_stream endpoint from Cloudflare JavaScript challenges (requests include valid OAuth Bearer tokens)
  2. Using a separate non-challenge-protected domain for the voice stream (similar to api.anthropic.com)
  3. Adding a Cloudflare bypass token/header for authenticated CLI clients

View original on GitHub ↗

This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗