nats-io/nats-server · error
enforceMsgPerSubjectLimit took %v
Error message
enforceMsgPerSubjectLimit took %v
What it means
A performance watchdog, not an error: enforceMsgPerSubjectLimit (re-applying max msgs per subject across all blocks, typically on recovery or config update) exceeded 1 minute. It indicates a very large subject-space being swept under lock.
Source
Thrown at server/filestore.go:5925
}
if removed, err := fs.deleteFirstMsg(); err != nil {
return err
} else if !removed {
return fs.rebuildFirst()
}
}
return nil
}
// Will make sure we have limits honored for max msgs per subject on recovery or config update.
// We will make sure to go through all msg blocks etc. but in practice this
// will most likely only be the last one, so can take a more conservative approach.
// Lock should be held.
func (fs *fileStore) enforceMsgPerSubjectLimit(fireCallback bool) error {
start := time.Now()
defer func() {
if took := time.Since(start); took > time.Minute {
fs.warn("enforceMsgPerSubjectLimit took %v", took.Round(time.Millisecond))
}
}()
maxMsgsPer := uint64(fs.cfg.MaxMsgsPer)
// We may want to suppress callbacks from remove during this process
// since these should have already been deleted and accounted for.
if !fireCallback {
cb := fs.scb
fs.scb = nil
defer func() { fs.scb = cb }()
}
var numMsgs uint64
// collect all that are not correct.
needAttention := stree.NewSubjectTree[uint64]()
fblk, lblk := uint32(math.MaxUint32), uint32(0)View on GitHub (pinned to 3a66a489d2)
Solutions
- Review the MaxMsgsPerSubject limit against the number of distinct subjects
- Batch or reduce the stream's subject cardinality
- Take a CPU profile during recovery if the slowness is unexpected
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at server/filestore.go:5925 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/03f035fdf53ea527.
Report an issue: GitHub.