WebSocket Close Codes — Understanding Connection Termination Status Codes
In this tutorial, you will learn about Websocket Close Codes. We cover key concepts, practical examples, and best practices to help you master this topic.
WebSocket close codes are 16-bit integers sent in the close frame that indicate why a connection was terminated, with standard codes for normal closure, protocol errors, and policy violations.
What You'll Learn
- The standard WebSocket close codes and their meanings
- Which codes are reserved and must not be used
- How to send and interpret close codes
Why It Matters
Proper close code handling helps diagnose connection issues. A 1001 (going away) means the client navigated elsewhere. A 1008 (policy violation) indicates a security issue. Without codes, you cannot distinguish normal disconnections from errors.
Close Code Reference
CLOSE_CODES = {
1000: {'name': 'Normal Closure', 'description': 'Connection closed normally'},
1001: {'name': 'Going Away', 'description': 'Client navigated away or server shutting down'},
1002: {'name': 'Protocol Error', 'description': 'Protocol violation'},
1003: {'name': 'Unsupported Data', 'description': 'Received unsupported data type'},
1005: {'name': 'No Status Received', 'description': 'No close code was provided'},
1006: {'name': 'Abnormal Closure', 'description': 'Connection closed without close frame'},
1007: {'name': 'Invalid Frame Payload Data', 'description': 'Invalid UTF-8 or inconsistent data'},
1008: {'name': 'Policy Violation', 'description': 'Message violates server policy'},
1009: {'name': 'Message Too Big', 'description': 'Message exceeds maximum size'},
1010: {'name': 'Mandatory Extension', 'description': 'Client required extension not negotiated'},
1011: {'name': 'Internal Server Error', 'description': 'Unexpected server condition'},
1012: {'name': 'Service Restart', 'description': 'Server is restarting'},
1013: {'name': 'Try Again Later', 'description': 'Temporary server condition'},
1014: {'name': 'Bad Gateway', 'description': 'Server acting as gateway received invalid response'},
1015: {'name': 'TLS Handshake Failure', 'description': 'TLS handshake could not be completed'},
}
def describe_close_code(code):
"""Get a human-readable description of a close code"""
info = CLOSE_CODES.get(code)
if info:
return f"{code}: {info['name']} - {info['description']}"
if code >= 3000 and code <= 3999:
return f"{code}: Registered (library/framework specific)"
elif code >= 4000 and code <= 4999:
return f"{code}: Private (application specific)"
else:
return f"{code}: Reserved (not to be used)"
Handling Close Frames
def handle_close_frame(payload):
"""Parse a WebSocket close frame payload"""
if len(payload) >= 2:
close_code = int.from_bytes(payload[:2], 'big')
reason = payload[2:].decode('utf-8', errors='replace')
return {'code': close_code, 'reason': reason, 'description': describe_close_code(close_code)}
return {'code': 1005, 'reason': '', 'description': 'No status code provided'}
def send_close(ws, code=1000, reason=''):
"""Send a WebSocket close frame with proper code"""
payload = bytearray()
payload.extend(code.to_bytes(2, 'big'))
payload.extend(reason.encode('utf-8'))
ws.send(payload, opcode=8)
Application-Specific Close Codes
# Application-specific close codes (4000-4999)
APP_CLOSE_CODES = {
4000: 'Session expired - please re-authenticate',
4001: 'Rate limit exceeded',
4002: 'Insufficient permissions',
4003: 'Invalid subscription tier',
4004: 'Concurrent connections limit reached',
4005: 'Client version outdated',
4006: 'Server maintenance in progress',
}
def send_application_close(ws, code, reason=None):
"""Send an application-specific close"""
if code not in APP_CLOSE_CODES:
raise ValueError(f"Unknown close code: {code}")
reason = reason or APP_CLOSE_CODES[code]
send_close(ws, code, reason)
def is_valid_close_code(code):
"""Check if a close code is valid"""
if code in (1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011):
return True
return 3000 <= code <= 4999
Common Mistakes
1. Using Reserved Codes
Codes 0-999 and 1016-2999 are reserved. Using them causes protocol violations. Stick to standard codes (1000-1015) or private range (4000-4999).
2. Sending a Close Frame with Invalid UTF-8 Reason
The reason text in a close frame must be valid UTF-8. Invalid UTF-8 in the close reason is a protocol error.
3. Not Sending a Close Frame
Abruptly closing the TCP connection without a close frame results in code 1006 (Abnormal Closure). Always send a close frame.
4. Ignoring Close Timeouts
After sending a close frame, the server waits for a close frame from the client. If not received within a timeout, the server should close the TCP connection.
5. Using Close Code 1005 Programmatically
1005 means "no status received" and must never be sent. It is only used when no close frame was received.
Practice Questions
- What close code indicates a normal closure?
- What code indicates a policy violation?
- What is the private range for application-specific codes?
- What does code 1006 mean?
- Can you send a close frame without a code?
Answers
- 4000-4999. 4. Abnormal Closure (connection closed without close frame). 5. No, if you send a close frame, it must include a 2-byte status code.
Challenge
Build a WebSocket connection monitor that: logs all close frames with their codes and reasons, categorizes closures as normal, error, or application-specific, tracks reconnection patterns, and provides analytics on connection stability.
FAQ
Mini Project
Build a WebSocket connection lifecycle manager that: tracks WebSocket connections from open to close, records close codes and reasons, categorizes closure types, implements auto-reconnect for abnormal closures (1006) but not for policy violations (1008), and provides a connection health dashboard.
What's Next
- Learn about WebSocket extensions like permessage-deflate
- Explore WebSocket implementation with Express and ws library
- Continue to Socket.IO for advanced real-time features
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro