Documentation

Errors and Troubleshooting

Catch operation failures, handle asynchronous server errors, and diagnose common SDK problems.

Before you start: follow Connecting and lifecycle. Register an error handler once per channel, and also catch rejected operation promises.

1. Catch the operation you started

Use these patterns in web/app.js: the first replaces a publish handler's error handling, and the second replaces the channel's error listener.

import { ConnectionError, textPayload } from "@useceleris/client";

try {
  await chat.publish({ payload: textPayload("Hello") });
} catch (error) {
  if (error instanceof ConnectionError && error.code === "NotConnected") {
    console.warn("Wait until connected before sending.");
  } else {
    console.error(error.name, error.message);
  }
}

Catch connect(), publish(), and presenceList() at their call sites. A failed initial connect rejects its caller without also firing onError. A failed presence query is likewise reported to its caller.

2. Handle server errors separately

import { ServerError } from "@useceleris/client";

const stopErrors = channel.events().onError((error) => {
  if (error instanceof ServerError) {
    console.error(error.type, error.subType, error.message);
    switch (error.type) {
      case "PermissionDeniedError":
        console.warn(
          "Check the server-issued channel and segment permissions."
        );
        break;
      case "MessageSizeLimitError":
        console.warn("Reduce the payload size.");
        break;
      case "RateLimitError":
        // The SDK pauses and resends recent commands by itself.
        console.warn("Rate limited; reduce the publishing rate if this repeats.");
        break;
      default:
        console.warn("The server reported an error.");
    }
    return;
  }
  console.error(error.code, error.message);
});
// Later:
stopErrors();

A ServerError contains type, subType, message, and resource. It has no SDK code. Error types are open-ended, so retain a default branch for a newer server. A resource can be null, a string, a number, a bigint, or a nested array of these. Check its type before using it; numeric resources are not necessarily timestamps.

A permission denial can identify a command and segment. It does not identify which of several otherwise identical publishes caused the error. Presence-query errors are correlated internally and reject their query instead.

Server error text is for people, not programmatic parsing. Display it as text, never raw HTML; avoid exposing sensitive diagnostic details in shared logs. Server errors leave the connection open.

3. Choose the right response

SDK codeResponse
ConfigurationFix invalid input or malformed credential output; retrying unchanged input will not help
NotConnectedWait for a connection; there is no offline queue
TimeoutCheck the credential endpoint/network or query deadline
CancelledUsually an intentional abort or close; do not automatically restart cancelled work
TransportCheck network and credential setup; this does not prove an authentication failure
BackpressureSlow production; 64 publishes are already waiting to be sent
OperationInProgressAvoid simultaneous connects or presence queries on one channel
DeliveryUnknownAcceptance is uncertain; do not blindly resend an irreversible operation
ProtocolErrorOne frame was dropped; the connection remains usable

A listener's synchronous exception is isolated and reported as a safe listener failure. Catch errors in asynchronous work started by your listeners yourself.

4. Diagnose common symptoms

SymptomFirst checks
First connect fails and nothing retriesExpected: offer an explicit Retry action from failed
Socket connects but messages are absentMatching channel/segment, held subscription, and read permission
Sender sees no received copyallowEcho defaults to false
Publish resolves, then an error appearsExpected for server refusals; resolution is only local acceptance
Presence events miss a userEvents are node-local; query a cluster-wide listing
Credentials were denied but error says TransportWebSocket handshake status is unavailable to the SDK
Updates are missing after recoveryReplay is bounded; reload authoritative application state
Presence request rejects with ConfigurationUse integer numbers: page 1–2147483647 and perPage 1–100; do not pass strings or bigints
Arithmetic throws about mixing numeric typesCounts and page figures are numbers; delivered timestamps are bigints. Do not mix them in arithmetic
JSON serialization throwsConvert bigint timestamps and bigint error-resource values to decimal strings; keep counts as numbers
Closed channel cannot reconnectObtain a new channel handle

See Reconnection and Recovery for which failures retry and how the budget works. Do not implement a competing retry timer while the channel is already reconnecting.

Use the numeric-value and JSON examples when storing SDK data. Number(timestamp) is not a general serialization fix: it can silently discard precision.

Expected: calling publish on an unconnected channel reaches the NotConnected branch without sending anything. Server errors are handled separately by type, not by parsing their message.

Next: Server-side usage, or the Client API for the full error surface.

We use Google Analytics cookies to understand how people use Celeris, only if you allow it. See our Cookie Policy.