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 code | Response |
|---|---|
Configuration | Fix invalid input or malformed credential output; retrying unchanged input will not help |
NotConnected | Wait for a connection; there is no offline queue |
Timeout | Check the credential endpoint/network or query deadline |
Cancelled | Usually an intentional abort or close; do not automatically restart cancelled work |
Transport | Check network and credential setup; this does not prove an authentication failure |
Backpressure | Slow production; 64 publishes are already waiting to be sent |
OperationInProgress | Avoid simultaneous connects or presence queries on one channel |
DeliveryUnknown | Acceptance is uncertain; do not blindly resend an irreversible operation |
ProtocolError | One 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
| Symptom | First checks |
|---|---|
| First connect fails and nothing retries | Expected: offer an explicit Retry action from failed |
| Socket connects but messages are absent | Matching channel/segment, held subscription, and read permission |
| Sender sees no received copy | allowEcho defaults to false |
| Publish resolves, then an error appears | Expected for server refusals; resolution is only local acceptance |
| Presence events miss a user | Events are node-local; query a cluster-wide listing |
| Credentials were denied but error says Transport | WebSocket handshake status is unavailable to the SDK |
| Updates are missing after recovery | Replay is bounded; reload authoritative application state |
| Presence request rejects with Configuration | Use integer numbers: page 1–2147483647 and perPage 1–100; do not pass strings or bigints |
| Arithmetic throws about mixing numeric types | Counts and page figures are numbers; delivered timestamps are bigints. Do not mix them in arithmetic |
| JSON serialization throws | Convert bigint timestamps and bigint error-resource values to decimal strings; keep counts as numbers |
| Closed channel cannot reconnect | Obtain 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.