Skip to main content

WebSocket Close Codes

When the server closes a WebSocket it carries a numeric close code. Clients should branch on this code, not on the close-reason text.

Standard close codes (RFC 6455)

CodeNameWhen you see itWhat to do
1001Going AwayServer is shutting down (deploy, rolling restart). Comes after a going_away JSON message with retryAfterMs.Wait the suggested interval, reconnect. Not an error.
1008Policy ViolationGeneric protocol violation. Rare; usually paired with a more specific 4xxx code.Inspect the close reason; fix the violation.
1009Message Too BigYou sent an inbound frame > 64 KB.Split the payload; the cap is per-frame, not per-session.

Application close codes (4xxx)

These are Metered-specific and documented as part of the wire protocol. RFC 6455 reserves the 4000–4999 range for application use.

CodeNameWhen you see itWhat to do
4001Invalid TokenJWT failed verification (bad signature, malformed, key not found).Check your sk_ signing secret + kid header. Re-mint and reconnect.
4002Token ExpiredJWT's exp has passed. The server force-closes ~250ms before exp.Mint a fresh token from your backend; reconnect.
4003Channel Not AuthorizedYou tried to subscribe to a channel outside your key's channelPatterns.Fix the key's patterns on the dashboard, or pick a different channel.
4010Over Concurrent LimitYour plan's maxConcurrentConnections hit AND overages are disabled (or balance exhausted with auto-recharge off).Wait and retry, or enable overages / upgrade the plan.
4011Over Message RatePer-connection token bucket emptied (sustained > 100 msg/sec or burst > 200). This is an abuse bound, not a billing limit.Throttle on the client. If you genuinely need >100 msg/sec sustained per peer, contact sales.
4012Account SuspendedThe customer's account is suspended (billing failure, ToS issue).Resolve in the dashboard. Reconnect attempts will keep failing until the account is reactivated.
4020Admin DisconnectA backend invoked DELETE /v1/peers/:id against this peer.Retry with a fresh token — typically a customer-issued logout / kick.

Pre-handshake HTTP rejections

Some failures happen before the WebSocket handshake completes, so the client sees an HTTP status instead of a close code:

HTTPReason
401Auth failed (invalid / expired / missing token, key not found, origin not allowed)
404Wrong path — the only valid upgrade endpoint is /v1
429Per-IP connect rate limit exceeded (anti-abuse)
500 / 503Internal failure during upgrade

Reconnect strategy

Close codeRecommended reconnect behavior
1001 Going AwayWait retryAfterMs from the going_away JSON message.
1008 / 1009Don't reconnect — fix the underlying issue first.
4001 / 4002Mint a fresh token, reconnect.
4003Don't reconnect — fix the channel auth on the backend.
4010Exponential backoff. Could be transient (other peers disconnecting frees a slot).
4011Exponential backoff. Don't immediately republish; you'll just trip the abuse bound again.
4012Stop. Show a user-facing message. The account is suspended.
4020Mint a fresh token; reconnect once. If the kick was the customer's intent (e.g., logout), don't auto-reconnect.

A reasonable default backoff: starting at 1s, exponential to 30s, plus ±20% jitter.