Realtime troubleshooting
Find why a live update did not reach your client, then fix the channel, token, connection, or publish call.
Most missed updates come from one of five places: the publish call, the token, the channel name, the topic list, or the connection. Work through the sections below in order. For a known-good publisher and subscriber to compare against, see the Quick start.
The client receives no messages
- Check that publishing ran. Open the function run. A
step.realtime.publish()call appears as a step in the trace. Forinngest.realtime.publish(), check that the code path ran and that the awaited call didn't throw. - Compare resolved channel names. A publisher on
job:123doesn't reach a subscriber onjob:124. Compare the channel in the publisher, the token, anduseRealtime. - Compare topics. The publisher, the token, and
useRealtime({ topics })must all include the topic. A token grants only its listed topics. - Check subscription timing. Realtime delivers messages only to clients connected when they're published. Wait for
connectionStatusto beopenbefore you start the work that publishes the first update. A tab that was hidden also misses messages published while it was paused. - Check the hook's retained messages.
messages.byTopic.statusholds only the lateststatusmessage.messages.allkeeps up tohistoryLimitmessages, 100 by default. AbufferIntervaldelays renders while it batches messages.
See Channels and topics for definitions and React hooks for hook state.
Publishing fails with a schema error
Compare the payload with the topic's required fields and types, and import the same channel definition in the publisher and subscriber. A runtime validator such as Zod rejects mismatched data when you publish. staticSchema<T>() checks types only at compile time, so a mismatch can reach the subscriber, which logs a validation error. If only the subscriber reports errors, check whether the publisher and subscriber deployed different schema versions.
The client cannot connect or gets an authorization error
- Mint on the server. Call
getClientSubscriptionToken()on your server and send the{ key, apiBaseUrl }object to the browser. The signing key must stay on the server. - Match the scope. The token's channel and topics must cover what
useRealtimerequests. Passchannelandtopicsto the hook too; the client token doesn't contain them. - Match the environment. Compare
apiBaseUrlwith the environment where the publisher runs. Locally, setINNGEST_DEV=1on the server that mints tokens. - Refresh tokens. Pass a token factory so the hook gets a fresh token when it reconnects.
Never mint a token for an unchecked channel ID from the browser. See Subscription tokens.
The connection closes or keeps reconnecting
Inspect connectionStatus and error.
pausedcomes fromenabled: falseor a hidden tab whilepauseOnHiddenistrue.pauseReasonsays which.closedfollows a completed, failed, or cancelled run whileautoCloseOnTerminalistrue.errorcomes with a matchingerrorvalue.
The hook reconnects by default. If reconnecting fails, check the token factory, the user's current access, and apiBaseUrl. When the job or channel ID changes, pass the new channel or change the hook's key to reset state and reconnect. reset() clears retained messages, result, and error.
The UI shows repeated progress or tokens
inngest.realtime.publish() sends immediately and isn't memoized, so it publishes again when the surrounding work retries. A call outside any step can also repeat when the function resumes after a wait. To fix repeats:
- Use
step.realtime.publish(id, topic, data)for state changes and final results, with a stable, unique step ID. - Move immediate publishes inside
step.run(). - For a token stream, let the UI tolerate repeats, for example by resetting the streamed text when the step restarts.
A server-side subscriber receives nothing
Check the channel and topics passed to subscribe({ app: inngest, ... }) or inngest.realtime.subscribe(). Read the returned stream or pass onMessage; creating a subscription alone doesn't process messages. Pass onError to see connection errors, and subscribe before the work publishes. See Server-side subscriptions.
Capture useful facts
When you ask for help, include the resolved channel name, topic, function run ID, publish method, connectionStatus, error, the token route's response status, and whether the tab was hidden. Don't include token keys or signing keys.