Fix WebSocket Connection Failures in Claude Code

Your application uses WebSockets and the connection fails with errors like:

WebSocket connection to 'ws://localhost:3001' failed:
Error during WebSocket handshake: Unexpected response code: 400

Or in your server logs:

Error: listen EADDRINUSE :::3001
WebSocket: Invalid frame header

Quick Fix

Check the three most common causes:

# 1. Is the WS server running?
lsof -i :3001

# 2. Is the client connecting to the right URL?
grep -r "ws://" src/ --include="*.ts" --include="*.js"

# 3. Is a proxy interfering?
cat vite.config.ts

If using a dev server with a proxy, add WebSocket proxy support:

// vite.config.ts
export default defineConfig({
  server: {
    proxy: {
      '/ws': {
        target: 'ws://localhost:3001',
        ws: true,
      },
    },
  },
});

What Is Happening

WebSocket connections start as HTTP requests that "upgrade" to the WebSocket protocol. This upgrade handshake is where most failures occur. Common causes include:

  1. Missing upgrade handling: The server does not handle the HTTP upgrade request
  2. Proxy stripping headers: A reverse proxy or dev server strips the Upgrade and Connection headers
  3. CORS blocking: The server rejects the WebSocket origin
  4. Port mismatch: Client connects to the wrong port or the server is not listening
  5. SSL/TLS mismatch: Using ws:// when the page is served over HTTPS (requires wss://)

Step-by-Step Fix

Step 1: Verify the server setup

A correct Node.js WebSocket server looks like:

import { WebSocketServer } from 'ws';
import { createServer } from 'http';

const server = createServer();
const wss = new WebSocketServer({ server });

wss.on('connection', (ws) => {
  console.log('Client connected');
  ws.on('message', (data) => {
    ws.send(JSON.stringify({ echo: data.toString() }));
  });
});

server.listen(3001, () => {
  console.log('WebSocket server running on port 3001');
});

Step 2: Fix the client connection

// Auto-detect protocol
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const ws = new WebSocket(\`\${protocol}//\${window.location.host}/ws\`);

Step 3: Configure proxy for development

Next.js:

// next.config.js
module.exports = {
  async rewrites() {
    return [{ source: '/ws', destination: 'http://localhost:3001/ws' }];
  },
};

Step 4: Add reconnection logic

WebSocket connections drop. Production code needs automatic reconnection with exponential backoff:

class ReconnectingWebSocket {
  private ws: WebSocket | null = null;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 10;
  private baseDelay = 1000;

  constructor(private url: string) { this.connect(); }

  private connect(): void {
    this.ws = new WebSocket(this.url);
    this.ws.onopen = () => { this.reconnectAttempts = 0; };
    this.ws.onclose = () => {
      if (this.reconnectAttempts < this.maxReconnectAttempts) {
        const delay = this.baseDelay * Math.pow(2, this.reconnectAttempts);
        this.reconnectAttempts++;
        setTimeout(() => this.connect(), delay);
      }
    };
  }
}

Prevention

Test WebSocket connections with wscat before integrating with your frontend:

npx wscat -c ws://localhost:3001/ws

Paste your error into our Error Diagnostic for an instant fix.

Master Claude Code

Get lifetime access to all ClaudHQ tools, advanced workflows, and production-grade templates.

Get Lifetime Access

Written by the ClaudHQ team ยท Expert Claude Code guides and tools