nats-io/nats-server · error

JetStream cluster requires configured routes or solicited le

Error message

JetStream cluster requires configured routes or solicited leafnode for the system account

What it means

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.

Source

Thrown at server/jetstream_cluster.go:1273

	js := s.getJetStream()
	if js == nil {
		return NewJSNotEnabledForAccountError()
	}
	// Already set.
	if js.cluster != nil {
		return nil
	}

	s.Noticef("Starting JetStream cluster")
	// We need to determine if we have a stable cluster name and expected number of servers.
	s.Debugf("JetStream cluster checking for stable cluster name and peers")

	hasLeafNodeSystemShare := s.canExtendOtherDomain()
	if s.isClusterNameDynamic() && !hasLeafNodeSystemShare {
		return errors.New("JetStream cluster requires cluster name")
	}
	if s.configuredRoutes() == 0 && !hasLeafNodeSystemShare {
		return errors.New("JetStream cluster requires configured routes or solicited leafnode for the system account")
	}

	return js.setupMetaGroup()
}

// isClustered returns if we are clustered.
// Lock should not be held.
func (js *jetStream) isClustered() bool {
	// This is only ever set, no need for lock here.
	return js.cluster != nil
}

// isClusteredNoLock returns if we are clustered, but unlike isClustered() does
// not use the jetstream's lock, instead, uses an atomic operation.
// There are situations where some code wants to know if we are clustered but
// can't use js.isClustered() without causing a lock inversion.
func (js *jetStream) isClusteredNoLock() bool {
	return atomic.LoadInt32(&js.clustered) == 1

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Add `cluster { routes: [...] }` pointing at peer servers so the meta group can form.
  2. If single-node JetStream is intended, disable clustering (remove clustering config) — R1 streams work without it.
  3. If using leafnodes, configure a solicited leafnode connection that shares the system account (canExtendOtherDomain).
  4. Verify with `nats-server --config` startup logs that routes were actually parsed (look for 'Connected to' route messages).

Example fix

// before
cluster {
  name: "nats-cluster-a"
  listen: "0.0.0.0:6222"
}
// after
cluster {
  name: "nats-cluster-a"
  listen: "0.0.0.0:6222"
  routes: [
    "nats://nats-1:6222",
    "nats://nats-2:6222",
    "nats://nats-3:6222"
  ]
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate that routes or leafnode extension are configured before enabling JS clustering
hasRoutes := len(cfg.Cluster.Routes) > 0
hasLeafSystemShare := cfg.Leafnodes != nil && len(cfg.Leafnodes.Remotes) > 0 && sharesSystemAccount
if !hasRoutes && !hasLeafSystemShare {
    return errors.New("jetstream clustering requires cluster.routes or system-account leafnode")
}

Try / catch

// Go: fail fast at config load time
if err := server.Start(); err != nil && strings.Contains(err.Error(), "requires configured routes") {
    return fmt.Errorf("config error: add cluster.routes or a solicited system-account leafnode: %w", err)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/bc3bf9aa68863bf2. Report an issue: GitHub.