{"record":{"id":"fc09551842cb603a","repo":"nats-io/nats-server","slug":"duplicate-window-cannot-be-bigger-than-max-age","errorCode":null,"errorMessage":"duplicate window cannot be bigger than max age","messagePattern":"duplicate window cannot be bigger than max age","errorType":"error_code","errorClass":"JSPedanticError","httpStatus":null,"severity":"error","filePath":"server/stream.go","lineNumber":1967,"sourceCode":"\t}\n\tif cfg.MaxAge < 0 {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"max age can not be negative\"))\n\t}\n\tif cfg.MaxAge != 0 && cfg.MaxAge < 100*time.Millisecond {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"max age needs to be >= 100ms\"))\n\t}\n\n\tif cfg.Duplicates == 0 && cfg.Mirror == nil && len(cfg.Sources) == 0 {\n\t\tmaxWindow := StreamDefaultDuplicatesWindow\n\t\tif lim.Duplicates > 0 && maxWindow > lim.Duplicates {\n\t\t\tif pedantic {\n\t\t\t\treturn StreamConfig{}, NewJSPedanticError(fmt.Errorf(\"duplicate window limits are higher than current limits\"))\n\t\t\t}\n\t\t\tmaxWindow = lim.Duplicates\n\t\t}\n\t\tif cfg.MaxAge != 0 && cfg.MaxAge < maxWindow {\n\t\t\tif pedantic {\n\t\t\t\treturn StreamConfig{}, NewJSPedanticError(fmt.Errorf(\"duplicate window cannot be bigger than max age\"))\n\t\t\t}\n\t\t\tcfg.Duplicates = cfg.MaxAge\n\t\t} else {\n\t\t\tcfg.Duplicates = maxWindow\n\t\t}\n\t}\n\tif cfg.Duplicates < 0 {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"duplicates window can not be negative\"))\n\t}\n\t// Check that duplicates is not larger then age if set.\n\tif cfg.MaxAge != 0 && cfg.Duplicates > cfg.MaxAge {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"duplicates window can not be larger then max age\"))\n\t}\n\tif lim.Duplicates > 0 && cfg.Duplicates > lim.Duplicates {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf(\"duplicates window can not be larger then server limit of %v\",\n\t\t\tlim.Duplicates.String()))\n\t}\n\tif cfg.Duplicates > 0 && cfg.Duplicates < 100*time.Millisecond {","sourceCodeStart":1949,"sourceCodeEnd":1985,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream.go#L1949-L1985","documentation":"In pedantic mode, if no explicit Duplicates window is set and the effective duplicate window (default or account-limited) is larger than the stream's MaxAge, the server rejects the config: a duplicate window longer than max age is meaningless since messages expire before dedup tracking ends. Non-pedantic mode silently sets Duplicates = MaxAge.","triggerScenarios":"Pedantic stream create/update where cfg.Duplicates==0 (no mirror/sources), MaxAge is set and greater than 0 but smaller than maxWindow (StreamDefaultDuplicatesWindow, possibly capped by account limits). server/stream.go:1967.","commonSituations":"Streams configured with short retention (e.g. max_age=1m) that inherit the default 2-minute duplicate window; users unaware dedup window and max age interact; enabling pedantic validation exposing previously silent coercion.","solutions":["Set cfg.Duplicates <= cfg.MaxAge explicitly","Increase cfg.MaxAge to at least the desired duplicate window","Omit pedantic mode so the server silently sets Duplicates=MaxAge"],"exampleFix":"// before\nStreamConfig{Name: \"ORDERS\", MaxAge: time.Minute} // default window 2m > max age\n// after\nStreamConfig{Name: \"ORDERS\", MaxAge: time.Minute, Duplicates: time.Minute}","handlingStrategy":"validation","validationCode":"if cfg.MaxAge != 0 && cfg.Duplicates == 0 {\n    cfg.Duplicates = cfg.MaxAge // keep window <= max age\n} else if cfg.Duplicates > cfg.MaxAge && cfg.MaxAge != 0 {\n    cfg.Duplicates = cfg.MaxAge\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    var apiErr *nats.APIError\n    if errors.As(err, &apiErr) && apiErr.ErrorCode == nats.ErrorCodeJetStreamInvalidStreamConfig {\n        cfg.Duplicates = cfg.MaxAge\n        err = createStream(cfg)\n    }\n}","preventionTips":["Always keep Duplicates <= MaxAge when MaxAge is set","Set both fields together in a single config helper","Enable pedantic checks in CI so window/age mismatches surface before production"],"tags":["jetstream","stream-config","pedantic","validation","deduplication"],"backgroundTag":"jetstream-invalid-stream-config","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}