nats-io/nats-server · error

TTL state is outdated; attempting to recover using linear sc

Error message

TTL state is outdated; attempting to recover using linear scan (seq %d to %d)

What it means

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.

Source

Thrown at server/filestore.go:2346

	}
	if allowMsgSchedules {
		defer fs.scheduling.resetTimer()
	}

	// If only sources need recovering, then we can optimize to a backward scan.
	if sourcesRecover && !ttlRecover && !schedRecover {
		if fs.state.Msgs > 0 && sourcesSeq <= fs.state.LastSeq {
			fs.warn("Sourcing state is outdated; attempting to recover using backward scan (seq %d to %d)", sourcesSeq, fs.state.LastSeq)
			if err := fs.recoverSourcesBackwardScan(sourcesSeq, sourcesScan); err != nil {
				return err
			}
		}
		return nil
	}

	if fs.state.Msgs > 0 && scanSeq <= fs.state.LastSeq {
		if ttlRecover && ttlSeq <= fs.state.LastSeq {
			fs.warn("TTL state is outdated; attempting to recover using linear scan (seq %d to %d)", ttlSeq, fs.state.LastSeq)
		}
		if schedRecover && schedSeq <= fs.state.LastSeq {
			fs.warn("Message scheduling state is outdated; attempting to recover using linear scan (seq %d to %d)", schedSeq, fs.state.LastSeq)
		}
		if sourcesRecover && sourcesSeq <= fs.state.LastSeq {
			fs.warn("Sourcing state is outdated; attempting to recover using linear scan (seq %d to %d)", sourcesSeq, fs.state.LastSeq)
		}
		// Only consider sources that need recovering.
		update := func(iName string, sseq uint64, ident string) {
			if _, ok := sourcesScan[iName]; !ok {
				return
			}
			if sss, ok := fs.sources[iName]; ok {
				sss.Seq, sss.Ident = sseq, ident
			}
		}
		var (
			mb     *msgBlock

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. No action needed; the scan self-heals TTL state
  2. Ensure graceful shutdowns so state files are persisted
  3. On very large streams expect a one-time longer startup while the scan runs
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at server/filestore.go:2346 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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