nats-io/nats-server · error · JSStreamInvalidConfigError

duplicates window can not be larger then server limit of %v

Error message

duplicates window can not be larger then server limit of %v

What it means

If the server (or account/template limits) defines a maximum Duplicates window (lim.Duplicates > 0), validation rejects any configured window larger than that server-side limit. This keeps duplicate-detection caches from growing beyond operational limits imposed via server config, account limits, or stream templates. Returned as a JSStreamInvalidConfigError including the limit value in the message.

Source

Thrown at server/stream.go:1982

		}
		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"))
	}
	if lim.Duplicates > 0 && cfg.Duplicates > lim.Duplicates {
		return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("duplicates window can not be larger then server limit of %v",
			lim.Duplicates.String()))
	}
	if cfg.Duplicates > 0 && cfg.Duplicates < 100*time.Millisecond {
		return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("duplicates window needs to be >= 100ms"))
	}

	if cfg.DenyPurge && cfg.AllowRollup {
		return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("roll-ups require the purge permission"))
	}

	// Counter is not compatible with some settings.
	if cfg.AllowMsgCounter {
		if cfg.Discard == DiscardNew {
			return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("counter stream cannot use discard new"))
		}
		if cfg.AllowMsgTTL {
			return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("counter stream cannot use message TTLs"))
		}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Read the effective limits (AccountInfo / JetStream limits) and clamp Duplicates to the reported limit.
  2. Lower StreamConfig.Duplicates to at or below the server limit shown in the error message.
  3. Ask the operator to raise the duplicates limit in the account limits if a longer window is genuinely needed.
  4. Make Duplicates configurable per environment rather than hardcoded.

Example fix

// before
 StreamConfig{Name: "ORDERS", Duplicates: 10 * time.Minute} // account limit: 2m
// after
 StreamConfig{Name: "ORDERS", Duplicates: 2 * time.Minute}
Defensive patterns

Strategy: validation

Validate before calling

info, err := js.AccountInfo(ctx)
if err != nil {
    return err
}
if max := info.Limits.StreamLimits.Duplicates; max > 0 && cfg.Duplicates > max {
    cfg.Duplicates = max
}

Try / catch

var scErr *jetstream.JSApiError
if _, err := js.CreateStream(ctx, cfg); errors.As(err, &scErr) && strings.Contains(scErr.Description, "duplicates window can not be larger then server limit") {
    return fmt.Errorf("reduce Duplicates to the account limit: %w", err)
}

Prevention

When it happens

Trigger: AddStream/UpdateStream with StreamConfig.Duplicates exceeding the duplicates limit from JetStreamAccountLimits or StreamLimits (e.g. requesting 10m when the account caps duplicates at 2m).

Common situations: Shared/multi-tenant NATS deployments where operators cap duplicate windows per account; deploying an app with a hardcoded large Duplicates value into a cluster with tighter limits than the dev environment.

Related errors


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