Documentation

Errors and Troubleshooting

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

Before you start: follow Connection and lifecycle. Register an error listener once per channel. Also check the errors that your calls return.

Every error that the SDK detects is a *celeris.Error with a stable Code. Match it with errors.Is(err, celeris.ErrTimeout) and the other sentinels, never on message text. Messages name the field and the rule that failed. They never repeat your input, a credential, or server text. Errors that the server sends are a *celeris.ServerError instead.

1. Check the call you made

if err := chat.Publish(ctx, celeris.TextPayload("Hello")); errors.Is(err, celeris.ErrNotConnected) {
    fmt.Println("Wait until connected before sending.")
} else if err != nil {
    fmt.Println(err)
}

Check Connect, Publish, and PresenceList where you call them. A failed initial connect returns its error to the caller and does not also reach OnError. The SDK likewise reports a failed presence query to its caller.

2. Handle server errors separately

stopErrors := channel.Events().OnError(func(err error) {
    serverError, ok := errors.AsType[*celeris.ServerError](err)

    if !ok {
        fmt.Println(err)

        return
    }

    fmt.Println(serverError.Type, serverError.SubType, serverError.Message)

    switch serverError.Type {
    case celeris.PermissionDeniedError:
        fmt.Println("Check the server-issued channel and segment permissions.")
    case celeris.MessageSizeLimitError:
        fmt.Println("Reduce the payload size.")
    case celeris.RateLimitError:
        // The SDK pauses and resends recent commands by itself.
        fmt.Println("Rate limited; publish less often if this repeats.")
    default:
        fmt.Println("The server reported an error.")
    }
})

// Later:
stopErrors()

A ServerError carries Type, SubType (the command it answers, or ""), and Message (the server's own text). Resource is what that command names, such as the segment. A ServerError has no Code. Match it with errors.AsType. Error types are open-ended, so retain a default branch for a newer server. A resource can be nil, a string, an int32, an int64, or a []any of these values. Check its type before you use it.

A permission denial can identify a command and a segment. It does not identify which of several otherwise identical publishes caused the error. The SDK correlates presence-query errors internally. Those errors return from PresenceList instead. Server error text is for people, not for programs. Show it as text, never as raw HTML. Server errors leave the connection open.

3. Choose the right response

SentinelResponse
ErrConfigurationFix the invalid argument or credential. A retry with unchanged input does not help
ErrNotConnectedWait for a connection, then try again. A publish waits in the queue only while the channel is reconnecting
ErrTimeoutCheck the credential endpoint and network, the query deadline, or your context's deadline
ErrCancelledYour context ended, or the channel closed during the operation. Do not automatically restart canceled work
ErrTransportCheck network and credential setup. This does not prove an authentication failure
ErrBackpressureSlow production. The publish queue (PublishQueueSize, 64 by default) is full, or a presence query found the writer full or paused
ErrOperationInProgressDo not start simultaneous connects or presence queries on one channel
ErrDeliveryUnknownAcceptance is uncertain. Do not blindly resend an irreversible operation
ErrProtocolOne frame was dropped. The connection remains usable. Field and Offset locate the failure
*ServerErrorAn error that the server sent. See step 2

The SDK recovers a panic in a listener and reports it through OnError as ErrTransport. Recover panics in goroutines that your listeners start. A nil listener registration panics at once. That is a programming error.

4. Diagnose common symptoms

SymptomFirst checks
First connect fails and nothing retriesThis is expected. Call Connect again from failed
Socket connects but messages are absentChannel/segment match, a a held subscription, and read permission
Sender sees no received copyAllowEcho defaults to false
Publish returns nil, then an error arrivesExpected for server refusals. A nil return is only local acceptance
PresenceList always returns ErrTimeoutThe query runs inside a listener. Call it from your own goroutine
Presence events miss a userYou get events only for joins and leaves while you hold presence. Query a cluster-wide listing
Credentials were denied but the error says TransportThe handshake status is unavailable to the SDK
Messages are absent after recoveryReplay is bounded. Reload authoritative application state
Channel stops in failed after a connection lossOnError gives the cause. Recovery used all MaximumReconnectAttempts (10 by default), or a failure other than ErrTransport or ErrTimeout stopped it. Call Connect again
PresenceList returns ErrConfigurationpage must be at least 1, and perPage must be from 1 to 100
A closed channel cannot reconnectObtain a new channel from the client

See Reconnection and Recovery for which failures retry. Do not run your own retry loop while the channel is in the reconnecting state.

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

We use Google cookies for analytics and for advertising measurement, only if you allow them. Until you choose, Google sets no cookies. Refer to our Cookie Policy.