nats-io/nats-server · error
message overrun
Error message
message overrun
What it means
Thrown during block load/recovery while scanning the raw message buffer: the scan position plus the fixed message header size (msgHdrSize) extends past the buffer end, meaning a truncated or partial header was found. The store rejects the block content rather than parsing a corrupt record.
Source
Thrown at server/filestore.go:6482
buf := mb.cache.buf
nbuf := getMsgBlockBuf(len(buf))
// Recycle our nbuf when we are done.
defer recycleMsgBlockBuf(nbuf)
var le = binary.LittleEndian
var firstSet bool
var last uint64
var msgs uint64
fseq := atomic.LoadUint64(&mb.first.seq)
lseq := atomic.LoadUint64(&mb.last.seq)
isDeleted := func(seq uint64) bool {
return seq == 0 || seq&ebit != 0 || mb.dmap.Exists(seq) || seq < fseq
}
for index, lbuf := uint32(0), uint32(len(buf)); index < lbuf; {
if index+msgHdrSize > lbuf {
return fmt.Errorf("message overrun")
}
hdr := buf[index : index+msgHdrSize]
rl, slen := le.Uint32(hdr[0:]), int(le.Uint16(hdr[20:]))
hasHeaders := rl&hbit != 0
// Clear any headers bit that could be set.
rl &^= hbit
shlen := slen
if hasHeaders {
shlen += 4
}
dlen := int(rl) - msgHdrSize
// Do some quick sanity checks here.
if dlen < 0 || shlen > (dlen-recordHashSize) || dlen > int(rl) || index+rl > lbuf || rl > rlBadThresh {
return fmt.Errorf("sanity check failed")
}
// Only need to process non-deleted messages.
seq := le.Uint64(hdr[4:])
ts := int64(le.Uint64(hdr[12:]))View on GitHub (pinned to 3a66a489d2)
Solutions
- Stop the server and run the JetStream file-store consistency checker / reset the affected stream (delete stream files so it re-creates)
- Restore the store directory from a consistent backup taken while the server was stopped
- Never copy or rsync live JetStream data directories; take snapshots offline
- Check the underlying filesystem/disk for corruption (fsck, SMART)
Defensive patterns
Strategy: validation
Validate before calling
// Before restart/recovery, ensure store files were not copied or truncated live: // 1) stop the server, 2) verify file sizes match metadata, 3) back up before recovery. // There is no pre-call API check; guard the environment instead.
Try / catch
// Go: on recovery error, reset the affected stream rather than retrying
if err := recoverStream(storeDir, streamName); err != nil {
if strings.Contains(err.Error(), "message overrun") {
// block file truncated: restore backup or reset stream
}
return err
} Prevention
- Never copy/rsync live JetStream data directories
- Shut down cleanly; avoid kill -9 on jetstream nodes
- Use fsync-friendly storage and UPS to survive power loss
- Take backups only while the server is stopped
When it happens
Trigger: Recovering a message block whose file was truncated mid-header (crash before flush, partial write, or externally truncated file) so len(buf) - index < msgHdrSize.
Common situations: Power loss / kill -9 without fsync landing, copying store files while the server is running, restore from an inconsistent backup, disk corruption.
Related errors
- sanity check failed
- failed to load block from disk: %w
- failed to decompress block: %w
- rebuildState for block %d failed: %w
- bad index file
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/8cff224f000c2aa9.
Report an issue: GitHub.