Skip to main content

WebSocket Connection Closes Before Establishment - Troubleshooting Guide

Overview

When a WebSocket connection closes immediately after creation (before establishment), it typically indicates one of several common issues. This guide helps diagnose and resolve these problems.

Common Causes & Solutions

1. Server Rejection (Most Common)

Symptoms:

  • Connection closes within 0-100ms
  • Close code: 1002 (Protocol error), 1008 (Policy violation), or 1011 (Server error)
  • Console logs show immediate closure

Possible Causes:

// Invalid endpoint
wss://pipeline.aiqlick.com/ws/pipeline/invalid-client-id

// Authentication failure
wss://pipeline.aiqlick.com/ws/pipeline/unauthorized-client

// Server overload/rate limiting
// Server returns 429 Too Many Requests equivalent

Solutions:

  • Verify the WebSocket endpoint URL is correct
  • Check client ID format and authentication
  • Implement exponential backoff (already implemented)
  • Contact server administrator about rate limiting

2. Network/Firewall Issues

Symptoms:

  • Connection closes within 100-1000ms
  • Close code: 1006 (Abnormal closure)
  • Network errors in browser console

Possible Causes:

  • Corporate firewall blocking WebSocket connections
  • Proxy server not supporting WebSocket upgrade
  • Network instability or packet loss

Solutions:

// Test basic connectivity first
const testConnectivity = async () => {
try {
await fetch("https://pipeline.aiqlick.com", {
method: "HEAD",
signal: AbortSignal.timeout(5000),
})
console.log("Basic HTTP connectivity: OK")
} catch (error) {
console.error("Basic connectivity failed:", error)
}
}

3. SSL/TLS Issues

Symptoms:

  • Close code: 1015 (TLS handshake failed)
  • Browser security errors
  • Mixed content warnings

Possible Causes:

  • Connecting to WSS from HTTP page
  • Invalid SSL certificate
  • Outdated TLS version

Solutions:

// Check protocol compatibility
if (location.protocol === "http:" && wsUrl.startsWith("wss:")) {
console.error("Cannot connect to secure WebSocket from insecure page")
// Use HTTPS or switch to ws:// (not recommended for production)
}

4. Browser/Client Issues

Symptoms:

  • Immediate rejection
  • Browser compatibility errors
  • Resource exhaustion

Possible Causes:

  • Too many concurrent WebSocket connections
  • Browser WebSocket limit exceeded
  • Client-side blocking (ad blockers, security software)

Solutions:

// Check WebSocket limits
if (navigator.hardwareConcurrency && navigator.hardwareConcurrency < 2) {
console.warn("Low system resources detected")
}

// Clean up existing connections
const cleanup = () => {
if (wsRef.current) {
wsRef.current.close(1000, "Cleanup")
wsRef.current = null
}
}

Enhanced Debugging Implementation

1. Connection Timing Analysis

const connectionStartTime = Date.now()

ws.onclose = (event) => {
const connectionDuration = Date.now() - connectionStartTime

if (connectionDuration < 100) {
console.error("IMMEDIATE REJECTION: Server rejected connection instantly")
console.error(
"Likely causes: Invalid endpoint, authentication failure, server overload"
)
} else if (connectionDuration < 1000) {
console.error("EARLY CLOSURE: Connection failed during handshake")
console.error("Likely causes: Network/firewall issues, SSL problems")
} else {
console.error("TIMEOUT CLOSURE: Connection attempt timed out")
console.error("Likely causes: Server overload, network congestion")
}
}

2. Detailed Error Codes

const getCloseCodeMeaning = (code: number): string => {
const meanings = {
1000: "Normal closure",
1001: "Going away (server shutdown)",
1002: "Protocol error (invalid WebSocket frame)",
1003: "Unsupported data type",
1005: "No status received (abnormal)",
1006: "Abnormal closure (network issue)",
1007: "Invalid frame payload data",
1008: "Policy violation (blocked by server)",
1009: "Message too big",
1010: "Mandatory extension missing",
1011: "Internal server error",
1012: "Service restart",
1013: "Try again later (temporary overload)",
1014: "Bad gateway (proxy issue)",
1015: "TLS handshake failed",
}

return meanings[code] || `Unknown code (${code})`
}

3. Pre-Connection Validation

const validateConnection = async (): Promise<boolean> => {
// Check basic network
if (!navigator.onLine) {
console.error("No internet connection")
return false
}

// Check protocol compatibility
if (location.protocol === "http:" && wsUrl.startsWith("wss:")) {
console.error("SSL/TLS mismatch")
return false
}

// Test HTTP connectivity
try {
await fetch(httpEquivalent, {
method: "HEAD",
signal: AbortSignal.timeout(3000),
})
} catch (error) {
console.error("HTTP connectivity test failed:", error)
return false
}

return true
}

Current Implementation Features

1. Rate Limiting Protection

  • Minimum 3-second interval between attempts
  • Maximum 5 reconnection attempts
  • Exponential backoff: 2s, 4s, 8s, 16s, 32s

2. Comprehensive Error Logging

console.log("Connection attempt details:", {
url: wsUrl,
clientId: clientId,
attempt: reconnectCountRef.current + 1,
maxAttempts: maxReconnectAttempts,
lastAttempt: new Date(lastConnectionAttemptRef.current).toISOString(),
timeSinceLastAttempt: Date.now() - lastConnectionAttemptRef.current,
})

3. Connection Timeout Protection

  • 15-second connection timeout
  • Prevents browser hanging
  • Clear error messaging

4. State Management

  • Four-state tracking: disconnected/connecting/connected/error
  • Visual indicators for each state
  • Manual reconnect capability

Diagnostic Steps

Step 1: Enable Detailed Logging

// In browser console, enable verbose WebSocket logging
localStorage.setItem("debug", "websocket:*")

Step 2: Check Network Tab

  • Open browser DevTools → Network tab
  • Look for WebSocket connection entries
  • Check HTTP status codes and timing

Step 3: Use WebSocket Diagnostic Component

import { WebSocketDiagnostic } from "@components/cv/WebSocketDiagnostic"

// Use in development to test connectivity
;<WebSocketDiagnostic />

Step 4: Server-Side Verification

# Test WebSocket endpoint directly
wscat -c wss://pipeline.aiqlick.com/ws/pipeline/test-client-id

# Check server logs for rejection reasons
docker logs pipeline-service --tail=100 | grep WebSocket

Prevention Strategies

1. Connection Pooling

// Limit concurrent connections
const maxConcurrentConnections = 3
const activeConnections = new Set<WebSocket>()

const createConnection = () => {
if (activeConnections.size >= maxConcurrentConnections) {
throw new Error("Too many concurrent connections")
}
// ... create connection
}

2. Health Checks

// Regular connectivity tests
const healthCheck = setInterval(async () => {
if (!isConnected) {
const isHealthy = await testPipelineConnectivity()
if (isHealthy && reconnectCountRef.current < maxReconnectAttempts) {
reconnect()
}
}
}, 30000)

3. Graceful Degradation

// Fallback to HTTP polling if WebSocket fails repeatedly
const fallbackToPolling = () => {
if (reconnectCountRef.current >= maxReconnectAttempts) {
console.log("Falling back to HTTP polling")
// Implement HTTP-based alternative
}
}

Server-Side Considerations

1. Rate Limiting Configuration

# Example server-side rate limiting
WEBSOCKET_RATE_LIMIT = {
'connections_per_minute': 10,
'connections_per_hour': 100,
'message_rate_per_second': 5
}

2. Proper Error Responses

# Send meaningful close codes
if not authenticate(client_id):
await websocket.close(code=1008, reason="Authentication failed")

if rate_limited(client_ip):
await websocket.close(code=1013, reason="Rate limit exceeded")

3. Health Monitoring

# Monitor connection patterns
logger.info(f"WebSocket connection attempt: {client_id} from {client_ip}")
logger.warning(f"Connection rejected: {reason}")

Testing Scenarios

1. Invalid Client ID

// Test with malformed client ID
const invalidClientId = "invalid@client#id"

2. Rapid Reconnection

// Test rate limiting
for (let i = 0; i < 10; i++) {
setTimeout(() => connect(), i * 100)
}

3. Network Interruption

// Simulate network loss
navigator.connection &&
navigator.connection.addEventListener("change", () => {
console.log("Network status changed:", navigator.onLine)
})

Summary

Early WebSocket closures are usually caused by:

  1. Server rejection (authentication, rate limiting, invalid endpoint)
  2. Network issues (firewall, proxy, connectivity)
  3. SSL/TLS problems (certificate, protocol mismatch)
  4. Browser limitations (too many connections, security policies)

The enhanced implementation provides comprehensive debugging, rate limiting, and error handling to identify and resolve these issues effectively.