Docs

Errors

The error envelope, every error code with its retry guidance, and what WebSocket close codes like 1006 mean.

Every error the service returns carries one numeric code from the table below, over REST and over the WebSocket alike. The first two digits mirror the HTTP status family, so 40101 maps to a 401 response.

The envelope

REST errors return a JSON body:

{ "error": { "message": "capability does not permit publish on this channel", "code": 40301, "statusCode": 403 } }

Over the WebSocket the same code arrives in an error frame, and the SDKs surface it as an Error with a code property on whichever promise or channel the failure belongs to.

Error codes

Code Name Meaning Retry?
40001 BadFrame Malformed request, body, or channel name No, fix the request
40101 BadAuth Authentication failed, bad key or token No, fix the credential
40102 AuthExpired The token was valid and has expired Yes, after re-authenticating. The SDK does this itself when it has an authCallback
40300 Forbidden Authenticated but not permitted for this action No
40301 Capability The token’s capability doesn’t grant the operation No, widen the capability
40302 ChannelDenied The token’s capability doesn’t cover this channel No, widen the capability
40400 NotFound The referenced channel or app doesn’t exist No
42900 RateLimited A rate limit or quota was exceeded, see Limits Yes, back off first
50000 Server Unexpected server-side error Maybe, once
50001 Bootstrap The edge is still provisioning its streams Yes, retry shortly

The JavaScript SDK exports the table as ErrorCode, so handlers compare against names instead of numbers:

import { ErrorCode } from '@foony/realtime';

channel.publish('chat', data).catch((error) => {
  if (error.code === ErrorCode.RateLimited) {
    scheduleRetry();
  }
});

WebSocket close codes

The codes above describe application errors. The WebSocket itself can also close, and the close code says why:

Close code Meaning
1000, 1001 Normal closure, for example close() was called or the page navigated away
1006 Abnormal closure. The socket died without a close frame
4002 The SDK’s own keep-alive timeout. The server went silent, so the SDK cut the connection to reconnect

A WebSocket error 1006 is not a Foony error code, it’s the browser reporting that the connection dropped without a goodbye: a network change, a killed tab, a proxy cutting an idle socket. The SDK treats it as disconnected and reconnects with backoff, so occasional 1006 closes are normal background noise. A 1006 that happens on every connect during the handshake is different: it usually means something between the client and realtime.foony.io is blocking WebSockets entirely, like a corporate proxy or firewall, or the auth frame never got a reply. Check that plain wss:// connections work from that network, and watch connection.on for the reason on the state change.

Where errors surface in the SDK

Publishes reject with the error. Attach failures move the channel to the failed state with the error as the reason. Credential problems the SDK can’t fix on its own move the connection to failed, as described in Connections. Everything recoverable is retried internally, so if you see an error, it’s one the SDK needed you to know about.