{"record":{"id":"bc3bf9aa68863bf2","repo":"nats-io/nats-server","slug":"jetstream-cluster-requires-configured-routes-or-so","errorCode":null,"errorMessage":"JetStream cluster requires configured routes or solicited leafnode for the system account","messagePattern":"JetStream cluster requires configured routes or solicited leafnode for the system account","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/jetstream_cluster.go","lineNumber":1273,"sourceCode":"\tjs := s.getJetStream()\n\tif js == nil {\n\t\treturn NewJSNotEnabledForAccountError()\n\t}\n\t// Already set.\n\tif js.cluster != nil {\n\t\treturn nil\n\t}\n\n\ts.Noticef(\"Starting JetStream cluster\")\n\t// We need to determine if we have a stable cluster name and expected number of servers.\n\ts.Debugf(\"JetStream cluster checking for stable cluster name and peers\")\n\n\thasLeafNodeSystemShare := s.canExtendOtherDomain()\n\tif s.isClusterNameDynamic() && !hasLeafNodeSystemShare {\n\t\treturn errors.New(\"JetStream cluster requires cluster name\")\n\t}\n\tif s.configuredRoutes() == 0 && !hasLeafNodeSystemShare {\n\t\treturn errors.New(\"JetStream cluster requires configured routes or solicited leafnode for the system account\")\n\t}\n\n\treturn js.setupMetaGroup()\n}\n\n// isClustered returns if we are clustered.\n// Lock should not be held.\nfunc (js *jetStream) isClustered() bool {\n\t// This is only ever set, no need for lock here.\n\treturn js.cluster != nil\n}\n\n// isClusteredNoLock returns if we are clustered, but unlike isClustered() does\n// not use the jetstream's lock, instead, uses an atomic operation.\n// There are situations where some code wants to know if we are clustered but\n// can't use js.isClustered() without causing a lock inversion.\nfunc (js *jetStream) isClusteredNoLock() bool {\n\treturn atomic.LoadInt32(&js.clustered) == 1","sourceCodeStart":1255,"sourceCodeEnd":1291,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/jetstream_cluster.go#L1255-L1291","documentation":"enableJetStreamClustering returns this when JetStream clustering is enabled but the server has zero statically configured routes and no leafnode connection that shares the system account. Clustering needs peers: either explicit cluster routes or a solicited leafnode that can extend the system domain — otherwise the meta raft group would be a single node with no way to discover peers.","triggerScenarios":"Starting a server with JetStream clustering where `cluster.routes` is empty (and no route URLs from flags/-cluster config) and s.canExtendOtherDomain() is false, i.e. no solicited leafnode with system-account share is configured.","commonSituations":"Single-server configs that enable clustering without routes (should stay non-clustered); template/rendered configs where the routes list was dropped; operators expecting leafnode extension but the leaf config lacks the system account or is remote (not solicited).","solutions":["Add `cluster { routes: [...] }` pointing at peer servers so the meta group can form.","If single-node JetStream is intended, disable clustering (remove clustering config) — R1 streams work without it.","If using leafnodes, configure a solicited leafnode connection that shares the system account (canExtendOtherDomain).","Verify with `nats-server --config` startup logs that routes were actually parsed (look for 'Connected to' route messages)."],"exampleFix":"// before\ncluster {\n  name: \"nats-cluster-a\"\n  listen: \"0.0.0.0:6222\"\n}\n// after\ncluster {\n  name: \"nats-cluster-a\"\n  listen: \"0.0.0.0:6222\"\n  routes: [\n    \"nats://nats-1:6222\",\n    \"nats://nats-2:6222\",\n    \"nats://nats-3:6222\"\n  ]\n}","handlingStrategy":"validation","validationCode":"// Validate that routes or leafnode extension are configured before enabling JS clustering\nhasRoutes := len(cfg.Cluster.Routes) > 0\nhasLeafSystemShare := cfg.Leafnodes != nil && len(cfg.Leafnodes.Remotes) > 0 && sharesSystemAccount\nif !hasRoutes && !hasLeafSystemShare {\n    return errors.New(\"jetstream clustering requires cluster.routes or system-account leafnode\")\n}\n","typeGuard":null,"tryCatchPattern":"// Go: fail fast at config load time\nif err := server.Start(); err != nil && strings.Contains(err.Error(), \"requires configured routes\") {\n    return fmt.Errorf(\"config error: add cluster.routes or a solicited system-account leafnode: %w\", err)\n}","preventionTips":["Always list cluster.routes when clustering JetStream","For single-node JetStream, keep clustering disabled instead of empty routes","Verify route connections in startup logs after each deploy","Confirm leafnode remotes share the system account if relying on domain extension"],"tags":["jetstream","nats","configuration","clustering","routes"],"backgroundTag":"missing-config-value","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}