{"record":{"id":"dabd815d1877efcd","repo":"nats-io/nats-server","slug":"js-consumer-offline","errorCode":"JS_CONSUMER_OFFLINE","errorMessage":"consumer is offline","messagePattern":"consumer is offline","errorType":"error_code","errorClass":"JSConsumerOfflineReasonError","httpStatus":null,"severity":"error","filePath":"server/jetstream_api.go","lineNumber":4979,"sourceCode":"\t\t\treq.Config.Name = fmt.Sprintf(\"%s-%s\", req.Config.Name, createConsumerName())\n\t\t\tconsumerName = req.Config.Name\n\t\t}\n\t}\n\n\t// If the user provided an expected stream identity, reject the request on a mismatch.\n\tvar streamIdentity string\n\tif req.Config.Direct || req.Config.Sourcing {\n\t\tstreamIdentity = stream.identity()\n\t\tif reqIdentity := sliceHeader(JSStreamIdentity, hdr); len(reqIdentity) > 0 && bytesToString(reqIdentity) != streamIdentity {\n\t\t\tresp.Error = NewJSConsumerStreamIdentityMismatchError(streamIdentity)\n\t\t\ts.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))\n\t\t\treturn\n\t\t}\n\t}\n\n\tif o := stream.lookupConsumer(consumerName); o != nil {\n\t\tif o.offlineReason != _EMPTY_ {\n\t\t\tresp.Error = NewJSConsumerOfflineReasonError(errors.New(o.offlineReason))\n\t\t\ts.sendDelayedAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp), nil, errRespDelay)\n\t\t\treturn\n\t\t}\n\t\t// If the consumer already exists then don't allow updating the PauseUntil, just set\n\t\t// it back to whatever the current configured value is.\n\t\to.mu.RLock()\n\t\treq.Config.PauseUntil = o.cfg.PauseUntil\n\t\t// If a durable sourcing consumer is used, we need to reset the deliver policy.\n\t\tif req.Config.Sourcing && req.Config.Durable != _EMPTY_ {\n\t\t\treq.Config.DeliverPolicy = o.cfg.DeliverPolicy\n\t\t\treq.Config.OptStartSeq = o.cfg.OptStartSeq\n\t\t\treq.Config.OptStartTime = o.cfg.OptStartTime\n\t\t}\n\t\to.mu.RUnlock()\n\t}\n\n\t// Initialize/update asset version metadata.\n\tsetStaticConsumerMetadata(&req.Config)","sourceCodeStart":4961,"sourceCodeEnd":4997,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/jetstream_api.go#L4961-L4997","documentation":"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.","triggerScenarios":"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.","commonSituations":"Majority of cluster nodes down during maintenance; rolling downgrade leaving the consumer unsupported; newly restored cluster with pending leader elections.","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."],"exampleFix":"// before\n_, err := js.AddConsumer(\"ORDERS\", &nats.ConsumerConfig{Durable: \"proc\"})\nif err != nil {\n\tvar apiErr *nats.APIError\n\tif errors.As(err, &apiErr) && apiErr.ErrorCode == nats.JSConsumerOfflineErr {\n\t\t// restore quorum / roll forward, then retry\n\t}\n}","handlingStrategy":"validation","validationCode":"ci, err := js.ConsumerInfo(\"ORDERS\", \"proc\")\nif err != nil {\n\tvar apiErr *nats.APIError\n\tif errors.As(err, &apiErr) && apiErr.ErrorCode == nats.JSConsumerOfflineErr {\n\t\treturn fmt.Errorf(\"consumer offline: %s\", apiErr.Description)\n\t}\n}","typeGuard":"func isConsumerOfflineErr(err error) bool {\n\tvar apiErr *nats.APIError\n\treturn errors.As(err, &apiErr) && apiErr.ErrorCode == nats.JSConsumerOfflineErr\n}","tryCatchPattern":"_, err := js.UpdateConsumer(\"ORDERS\", cfg)\nif isConsumerOfflineErr(err) {\n\t// restore quorum / wait for leader, then retry with backoff\n}","preventionTips":["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."],"tags":["jetstream","consumer","cluster","quorum","offline"],"backgroundTag":"consumer-offline","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}