Errors and close codes

View Source

This page lists every failure mode the library can surface, together with what the library does about it and what you can do about it as an operator.

Parser errors

ws_frame:parse/2 returns {error, Reason, Parser}. The session turns each one into the mandated RFC 6455 close frame, sends it, and shuts the socket down. Your handler's terminate/2 receives normal.

ReasonClose codeMeaning
protocol_error1002RSV bits set with no extension, bad opcode, non-minimal length encoding, control frame > 125 bytes or fragmented, mask bit wrong for the role, continuation frame without an open fragment, etc.
invalid_utf81007Invalid UTF-8 in a text frame or in a close-frame reason.
message_too_big1009Single frame over max_frame, or accumulated fragments over max_message.
bad_close_code1002Close frame carrying a reserved or undefined code (1004, 1005, 1006, 1012–2999, 5000+).

Close codes (RFC 6455 §7.4)

The ws_close module gates which codes are legal on the wire.

1> ws_close:valid_on_wire(1000).
true
2> ws_close:valid_on_wire(1005).
false                             %% reserved: "no status"
3> ws_close:reason_name(1009).
message_too_big
CodeNameSource
1000normaleither peer
1001going_awayeither peer
1002protocol_errorsession on protocol violation
1003unsupported_datahandler
1004reservednever on the wire
1005no_statuslocal-only
1006abnormallocal-only
1007invalid_utf8session on bad UTF-8
1008policy_violationhandler
1009message_too_bigsession on size limit
1010extension_requiredclient
1011internal_errorserver
1015tls_handshakenever on the wire
3000–3999registeredapplication
4000–4999privateapplication

Handshake errors (HTTP/1.1)

ws_h1_upgrade:validate_request/1,2 returns {error, Reason} on any of these:

ReasonMeaning
missing_upgrade_headerNo Upgrade: at all.
{invalid_upgrade, Value}Upgrade: does not list websocket.
missing_connection_headerNo Connection: at all.
{invalid_connection, Value}Connection: does not list upgrade.
{unsupported_version, V}Sec-WebSocket-Version is not 13.
missing_sec_websocket_keyHeader absent.
bad_sec_websocket_keyHeader present but not 16 bytes once base64-decoded.
no_acceptable_subprotocolrequired_subprotocols was set and none of them was offered.

ws_h1_upgrade:validate_response/2 returns {error, Reason} for the client-side validation of a 101:

ReasonMeaning
{unexpected_status, N}Status line was not 101.
missing_upgrade_headerResponse missing Upgrade: websocket.
missing_connection_headerResponse missing Connection: upgrade.
missing_sec_websocket_acceptResponse missing Sec-WebSocket-Accept.

Additionally ws_client:connect/2 returns {error, sec_websocket_accept_mismatch} if the computed accept value does not match the server's.

Handshake errors (HTTP/2 / HTTP/3)

ws_h2_upgrade:validate_request/1,2 (and its ws_h3_upgrade alias):

ReasonMeaning
wrong_method:method is not CONNECT.
wrong_protocol:protocol is not websocket.
missing_scheme:scheme not present.
missing_authority:authority not present.
missing_path:path not present.
no_acceptable_subprotocolrequired_subprotocols was set and none matched.

ws_h2_upgrade:client_request/4 returns {error, peer_does_not_allow_connect_protocol} if you try to build an extended-CONNECT request against a peer that did not advertise SETTINGS_ENABLE_CONNECT_PROTOCOL = 1.

Transport errors

Transport I/O errors propagate through the session as {stop, {transport_error, Reason}, State} — the handler's terminate/2 is called with that tuple. The most common are closed (peer went away), timeout (only possible during the client handshake), and {tls_alert, _} when the TLS handshake fails.

If a custom transport does not implement recv/2 and the client needs it, ws_client:connect/2 returns {error, {transport_does_not_support_recv, Mod}}.

Size-limit errors

ReasonSource
handshake_too_bigServer pre-upgrade read over max_handshake_size (default 64 KiB).
handshake_response_too_bigClient 101 response read over max_handshake_size.
{inflate_too_big, MaxSize}ws_deflate:inflate/3,4 output exceeded the cap.