nats-io/nats-server · error · JSConsumerOfflineReasonError
JS_CONSUMER_OFFLINE
JS_CONSUMER_OFFLINE
Error message
consumer is offline
What it means
JS_CONSUMER_OFFLINE is returned on consumer create/update when the named durable consumer exists but its asset is offline (offlineReason set) — e.g. its raft group lacks quorum or the asset is unsupported. The consumer cannot be served or modified until it comes back online.
Source
Thrown at server/jetstream_api.go:4979
req.Config.Name = fmt.Sprintf("%s-%s", req.Config.Name, createConsumerName())
consumerName = req.Config.Name
}
}
// If the user provided an expected stream identity, reject the request on a mismatch.
var streamIdentity string
if req.Config.Direct || req.Config.Sourcing {
streamIdentity = stream.identity()
if reqIdentity := sliceHeader(JSStreamIdentity, hdr); len(reqIdentity) > 0 && bytesToString(reqIdentity) != streamIdentity {
resp.Error = NewJSConsumerStreamIdentityMismatchError(streamIdentity)
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
}
if o := stream.lookupConsumer(consumerName); o != nil {
if o.offlineReason != _EMPTY_ {
resp.Error = NewJSConsumerOfflineReasonError(errors.New(o.offlineReason))
s.sendDelayedAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp), nil, errRespDelay)
return
}
// If the consumer already exists then don't allow updating the PauseUntil, just set
// it back to whatever the current configured value is.
o.mu.RLock()
req.Config.PauseUntil = o.cfg.PauseUntil
// If a durable sourcing consumer is used, we need to reset the deliver policy.
if req.Config.Sourcing && req.Config.Durable != _EMPTY_ {
req.Config.DeliverPolicy = o.cfg.DeliverPolicy
req.Config.OptStartSeq = o.cfg.OptStartSeq
req.Config.OptStartTime = o.cfg.OptStartTime
}
o.mu.RUnlock()
}
// Initialize/update asset version metadata.
setStaticConsumerMetadata(&req.Config)View on GitHub (pinned to 3a66a489d2)
Solutions
- Restore quorum for the consumer's raft group (start the required JetStream servers) and wait for leader election.
- Read the offlineReason in the API error and server logs, then address that root cause.
- If unsupported after downgrade, roll forward to the newer version or recreate the consumer with a compatible config.
- Retry once `nats consumer info <stream> <consumer>` succeeds without the offline error.
Example fix
// before
_, err := js.AddConsumer("ORDERS", &nats.ConsumerConfig{Durable: "proc"})
if err != nil {
var apiErr *nats.APIError
if errors.As(err, &apiErr) && apiErr.ErrorCode == nats.JSConsumerOfflineErr {
// restore quorum / roll forward, then retry
}
} Defensive patterns
Strategy: validation
Validate before calling
ci, err := js.ConsumerInfo("ORDERS", "proc")
if err != nil {
var apiErr *nats.APIError
if errors.As(err, &apiErr) && apiErr.ErrorCode == nats.JSConsumerOfflineErr {
return fmt.Errorf("consumer offline: %s", apiErr.Description)
}
} Type guard
func isConsumerOfflineErr(err error) bool {
var apiErr *nats.APIError
return errors.As(err, &apiErr) && apiErr.ErrorCode == nats.JSConsumerOfflineErr
} Try / catch
_, err := js.UpdateConsumer("ORDERS", cfg)
if isConsumerOfflineErr(err) {
// restore quorum / wait for leader, then retry with backoff
} Prevention
- Ensure cluster quorum for consumer raft groups before maintenance.
- Act on the offlineReason in the API error instead of blind retries.
- Do not downgrade servers owning durable consumers.
- Use backoff + retry for consumer ops after failovers.
When it happens
Trigger: Consumer create/update while the consumer's raft group has no quorum or leader; consumer asset marked offline after a version downgrade; request arrives during failover before the new leader is elected.
Common situations: Majority of cluster nodes down during maintenance; rolling downgrade leaving the consumer unsupported; newly restored cluster with pending leader elections.
Related errors
- consumer closed
- consumer write error: %v
- unsupported consumer %q
- max_request_batch must be set if it's JetStream limits are s
- consumer name can not contain '.', '*', '>', '\', '/'
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/dabd815d1877efcd.
Report an issue: GitHub.