WebSocket close codes
When a WebSocket connection ends, the closing endpoint can send a Close frame containing a numeric status code and an optional reason string. These codes — defined in RFC 6455 and extended through the IANA registry — explain why the socket closed: a clean shutdown, a protocol error, an oversized message, or an application-specific reason of your own. Some codes are reserved and set only by the library (you must never send them yourself), and whole ranges are carved out for application use. Search the reference above by number or keyword.
How it works
A Close frame carries a 2-byte big-endian status code followed by an optional UTF-8 reason of up to 123 bytes. The protocol-defined codes live in 1000–2999. Within that, 1000 is a clean close, 1001–1011 cover protocol, data, policy, and server errors, and a few values (1005, 1006, 1015) are reserved — they describe what happened but must never be transmitted in a frame. The 3000–3999 range is for codes registered with IANA by libraries and frameworks, and 4000–4999 is entirely private: your application can assign its own meanings there without coordinating with anyone. Codes below 1000 are never used.
Quick reference: the key ranges
| Range | Owner | What it means |
|---|---|---|
| 1000 | Protocol | Normal, intentional close |
| 1001 | Protocol | Endpoint going away (server restart, tab closed) |
| 1002 | Protocol | Protocol error |
| 1003 | Protocol | Unacceptable data type (e.g. binary when only text expected) |
| 1005 | Reserved | No status code was present (library only, never sent) |
| 1006 | Reserved | Abnormal closure — no Close frame received (library only) |
| 1007 | Protocol | Invalid UTF-8 in a text frame |
| 1008 | Protocol | Policy violation |
| 1009 | Protocol | Message too large |
| 1011 | Protocol | Unexpected server error |
| 1015 | Reserved | TLS handshake failure (library only, never sent) |
| 3000–3999 | IANA registered | Library and framework codes (e.g. Stomp, MQTT adapters) |
| 4000–4999 | Application private | Your own application-specific reasons |
Common debugging scenarios
Client sees 1006 — what happened? The TCP connection dropped without a Close frame. Common causes: network interruption, load balancer timeout, server process killed abruptly. It is a connectivity event, not an application error. Add exponential backoff reconnect logic and log the reconnect attempt.
Server wants to reject an unauthenticated connection. Send a Close frame with code 4001 (or whatever your app defines for “unauthenticated”) immediately after the HTTP upgrade handshake completes. Do not leave the socket open and silently ignore messages.
Library or framework close codes in the 3000s. These are IANA-registered by the authors of specific toolkits (e.g. a message-queue bridge or a multiplexing layer). If you see an unfamiliar 3xxx code, check the library’s documentation rather than the RFC.
Tips and examples
- Close cleanly with
1000 Normal Closurewhen work is done, and let the peer echo a Close frame before the TCP teardown. - Treat
1006as a connectivity signal, not an application error — it means the socket dropped without a Close frame, so reconnect with backoff. - Reserve a
4000–4999code for each of your own shutdown reasons (e.g.4001= session expired,4002= kicked by admin) and document them for clients. - Keep reason strings short and human-readable for logs; never rely on parsing them programmatically since they are not standardized.
- Codes
1005,1006, and1015must never appear in an actual Close frame you send — they are set internally by the library to describe the event after the fact.