nats-io/nats-server · error · JSPedanticError

duplicate window limits are higher than current limits

Error message

duplicate window limits are higher than current limits

What it means

In pedantic mode, when no explicit Duplicates window is set (Duplicates==0, no mirror/sources), the default duplicate window (StreamDefaultDuplicatesWindow) may exceed the server's account limit lim.Duplicates; pedantic mode refuses the implicit coercion and returns this JSPedanticError instead of shrinking the window.

Source

Thrown at server/stream.go:1961

	}
	if cfg.MaxConsumers == 0 || cfg.MaxConsumers < -1 {
		if pedantic && cfg.MaxConsumers < -1 {
			return StreamConfig{}, NewJSPedanticError(fmt.Errorf("max_consumers must be set to -1"))
		}
		cfg.MaxConsumers = -1
	}
	if cfg.MaxAge < 0 {
		return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("max age can not be negative"))
	}
	if cfg.MaxAge != 0 && cfg.MaxAge < 100*time.Millisecond {
		return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("max age needs to be >= 100ms"))
	}

	if cfg.Duplicates == 0 && cfg.Mirror == nil && len(cfg.Sources) == 0 {
		maxWindow := StreamDefaultDuplicatesWindow
		if lim.Duplicates > 0 && maxWindow > lim.Duplicates {
			if pedantic {
				return StreamConfig{}, NewJSPedanticError(fmt.Errorf("duplicate window limits are higher than current limits"))
			}
			maxWindow = lim.Duplicates
		}
		if cfg.MaxAge != 0 && cfg.MaxAge < maxWindow {
			if pedantic {
				return StreamConfig{}, NewJSPedanticError(fmt.Errorf("duplicate window cannot be bigger than max age"))
			}
			cfg.Duplicates = cfg.MaxAge
		} else {
			cfg.Duplicates = maxWindow
		}
	}
	if cfg.Duplicates < 0 {
		return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("duplicates window can not be negative"))
	}
	// Check that duplicates is not larger then age if set.
	if cfg.MaxAge != 0 && cfg.Duplicates > cfg.MaxAge {
		return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("duplicates window can not be larger then max age"))

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Set cfg.Duplicates explicitly to a value <= the account's limits.Duplicates
  2. Raise the account's JetStream template duplicate window limit (account server config)
  3. Run without pedantic mode so the server caps maxWindow to lim.Duplicates silently

Example fix

// before
StreamConfig{Name: "ORDERS"} // duplicates window defaults higher than account limit
// after
StreamConfig{Name: "ORDERS", Duplicates: 2 * time.Minute}
Defensive patterns

Strategy: validation

Validate before calling

lim, _ := js.AccountLimits()
if cfg.Duplicates == 0 && lim.Duplicates > 0 && defaultDuplicatesWindow > lim.Duplicates {
    cfg.Duplicates = lim.Duplicates // pre-cap to stay pedantic-safe
}

Try / catch

if err != nil {
    var apiErr *nats.APIError
    if errors.As(err, &apiErr) && apiErr.ErrorCode == nats.ErrorCodeJetStreamInvalidStreamConfig {
        cfg.Duplicates = accountLimits.Duplicates
        err = createStream(cfg)
    }
}

Prevention

When it happens

Trigger: Stream create/update in pedantic mode where cfg.Duplicates==0, cfg.Mirror==nil, len(cfg.Sources)==0, and StreamDefaultDuplicatesWindow > account limits.Duplicates. server/stream.go:1961.

Common situations: Accounts with a lowered duplicate-window template limit creating streams that previously silently used the capped default; enabling pedantic validation in CI; multi-tenant deployments with per-account JetStream limits.

Related errors


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