{"record":{"id":"af38c26ce32b2025","repo":"nats-io/nats-server","slug":"ttl-state-is-outdated-attempting-to-recover-using","errorCode":null,"errorMessage":"TTL state is outdated; attempting to recover using linear scan (seq %d to %d)","messagePattern":"TTL state is outdated; attempting to recover using linear scan \\(seq (.+?) to (.+?)\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/filestore.go","lineNumber":2346,"sourceCode":"\t}\n\tif allowMsgSchedules {\n\t\tdefer fs.scheduling.resetTimer()\n\t}\n\n\t// If only sources need recovering, then we can optimize to a backward scan.\n\tif sourcesRecover && !ttlRecover && !schedRecover {\n\t\tif fs.state.Msgs > 0 && sourcesSeq <= fs.state.LastSeq {\n\t\t\tfs.warn(\"Sourcing state is outdated; attempting to recover using backward scan (seq %d to %d)\", sourcesSeq, fs.state.LastSeq)\n\t\t\tif err := fs.recoverSourcesBackwardScan(sourcesSeq, sourcesScan); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\tif fs.state.Msgs > 0 && scanSeq <= fs.state.LastSeq {\n\t\tif ttlRecover && ttlSeq <= fs.state.LastSeq {\n\t\t\tfs.warn(\"TTL state is outdated; attempting to recover using linear scan (seq %d to %d)\", ttlSeq, fs.state.LastSeq)\n\t\t}\n\t\tif schedRecover && schedSeq <= fs.state.LastSeq {\n\t\t\tfs.warn(\"Message scheduling state is outdated; attempting to recover using linear scan (seq %d to %d)\", schedSeq, fs.state.LastSeq)\n\t\t}\n\t\tif sourcesRecover && sourcesSeq <= fs.state.LastSeq {\n\t\t\tfs.warn(\"Sourcing state is outdated; attempting to recover using linear scan (seq %d to %d)\", sourcesSeq, fs.state.LastSeq)\n\t\t}\n\t\t// Only consider sources that need recovering.\n\t\tupdate := func(iName string, sseq uint64, ident string) {\n\t\t\tif _, ok := sourcesScan[iName]; !ok {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif sss, ok := fs.sources[iName]; ok {\n\t\t\t\tsss.Seq, sss.Ident = sseq, ident\n\t\t\t}\n\t\t}\n\t\tvar (\n\t\t\tmb     *msgBlock","sourceCodeStart":2328,"sourceCodeEnd":2364,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/filestore.go#L2328-L2364","documentation":"On recovery, the persisted per-message TTL tracking state is older than the message range present in the store (TTL bookkeeping did not survive the last shutdown). Rather than expiring messages incorrectly, the store re-derives TTL state by linearly scanning messages from ttlSeq to LastSeq.","triggerScenarios":"Thrown at server/filestore.go:2346 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["No action needed; the scan self-heals TTL state","Ensure graceful shutdowns so state files are persisted","On very large streams expect a one-time longer startup while the scan runs"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}