nats-io/nats-server · error · JSStreamInvalidConfigError

maximum replicas is %d

Error message

maximum replicas is %d

What it means

JetStream stream configuration validation rejects a stream whose Replicas count exceeds StreamMaxReplicas (the server's maximum supported R for mirrored/clustered streams). The server wraps it in a JSStreamInvalidConfigError during stream config normalization. This prevents creating or updating a stream with a replication factor the server cannot support.

Source

Thrown at server/stream.go:1915

		return cfg, NewJSStreamInvalidConfigError(fmt.Errorf("invalid discard policy"))
	}
	if _, err := cfg.Compression.MarshalJSON(); err != nil {
		return cfg, NewJSStreamInvalidConfigError(fmt.Errorf("invalid compression"))
	}

	// Make file the default.
	if cfg.Storage == 0 {
		cfg.Storage = FileStorage
	}
	if _, err := cfg.Storage.MarshalJSON(); err != nil {
		return cfg, NewJSStreamInvalidConfigError(fmt.Errorf("invalid storage type"))
	}

	if cfg.Replicas == 0 {
		cfg.Replicas = 1
	}
	if cfg.Replicas > StreamMaxReplicas {
		return cfg, NewJSStreamInvalidConfigError(fmt.Errorf("maximum replicas is %d", StreamMaxReplicas))
	}
	if cfg.Replicas < 0 {
		return cfg, NewJSReplicasCountCannotBeNegativeError()
	}
	if cfg.MaxMsgs == 0 || cfg.MaxMsgs < -1 {
		if pedantic && cfg.MaxMsgs < -1 {
			return StreamConfig{}, NewJSPedanticError(fmt.Errorf("max_msgs must be set to -1"))
		}
		cfg.MaxMsgs = -1
	}
	if cfg.MaxMsgsPer == 0 || cfg.MaxMsgsPer < -1 {
		if pedantic && cfg.MaxMsgsPer < -1 {
			return StreamConfig{}, NewJSPedanticError(fmt.Errorf("max_msgs_per_subject must be set to -1"))
		}
		cfg.MaxMsgsPer = -1
	}
	if cfg.MaxBytes == 0 || cfg.MaxBytes < -1 {
		if pedantic && cfg.MaxBytes < -1 {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Lower the stream's Replicas in the StreamConfig to a value <= StreamMaxReplicas (check the constant in your server version)
  2. If you need higher replication, upgrade the nats-server to a version with a higher StreamMaxReplicas
  3. If clusters/servers are the real intent, use raft placement/placement tags rather than inflating replicas

Example fix

// before
cfg := jetstream.StreamConfig{Name: "ORDERS", Replicas: 10}
// after
cfg := jetstream.StreamConfig{Name: "ORDERS", Replicas: 3}
Defensive patterns

Strategy: validation

Validate before calling

if cfg.Replicas < 0 || cfg.Replicas > jetstream.MaxReplicasCap { // check your server's StreamMaxReplicas
    return fmt.Errorf("replicas %d exceeds server maximum", cfg.Replicas)
}

Try / catch

err := createStream(cfg)
var apiErr *nats.APIError
if errors.As(err, &apiErr) && apiErr.ErrorCode == nats.ErrorCodeJetStreamInvalidStreamConfig {
    // surface a config-fix hint to the user
}

Prevention

When it happens

Trigger: Calling stream create/update API (JS API $JS.API.STREAM.CREATE/UPDATE) with config.replicas set higher than StreamMaxReplicas; e.g. submitting replicas=10 when the server max is lower. Occurs in the server-side config check (server/stream.go:1915) before the stream is persisted.

Common situations: Copy-pasted config from another deployment (e.g. cloud with higher replica cap); misreading replicas as 'number of servers'; accidental multiplication in config templating; upgrading clients that allow higher R than this server version supports.

Related errors


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