nats-io/nats-server · error
ErrIncompleteEntry
ErrIncompleteEntry
Error message
archive: entry not fully written
What it means
ErrIncompleteEntry means a Writer still has an open entry whose declared payload (HeaderSize+PayloadSize) has not been fully written. Writer.WriteHeader throws it if you start a new entry while the previous one still has bytes outstanding, and Writer.Close throws it if the stream is finalized with an unfinished entry. It protects the on-wire format: a reader would otherwise consume the next entry's header as payload.
Source
Thrown at server/archive/archive.go:33
import (
"bufio"
"encoding/binary"
"errors"
"io"
)
const MagicBytes = "NATSARC1"
// maxNameLen bounds the entry name length accepted when reading an archive,
// avoiding an unbounded allocation on corrupt or malicious input. The name is
// the only variable-length field read directly from the stream.
const maxNameLen = 1 << 20
var (
ErrClosed = errors.New("archive: closed")
ErrInvalidArchive = errors.New("archive: invalid archive stream")
ErrIncompleteEntry = errors.New("archive: entry not fully written")
ErrNoActiveEntry = errors.New("archive: no active entry")
ErrWriteTooLong = errors.New("archive: write exceeds declared entry size")
ErrNilHeader = errors.New("archive: nil header")
ErrNegativeEntrySize = errors.New("archive: negative entry size")
)
// Header describes one archive entry.
//
// On the wire each entry is the encoded header fields followed by the payload.
// HeaderSize and PayloadSize describe how that payload is split (e.g. message
// headers vs. body); the payload length is their sum and is not stored
// separately. Sequence is always encoded, with 0 meaning "unset".
type Header struct {
Name string
HeaderSize int64
PayloadSize int64
Timestamp int64
Sequence uint64View on GitHub (pinned to 3a66a489d2)
Solutions
- Write exactly HeaderSize+PayloadSize bytes for each entry before starting the next one; pad with zeros if the source is short.
- Track bytes written per entry and assert they match the declared sizes before calling WriteHeader again or Close.
- Restructure so WriteHeader is called only after the full payload is available in memory (buffer it), avoiding mid-entry aborts.
- If an entry must be abandoned mid-write, finish the declared size (write filler) since the Writer has no abort API.
Example fix
// before
w.WriteHeader(&archive.Header{Name: "a", PayloadSize: 100})
w.Write(buf[:40])
w.WriteHeader(next) // ErrIncompleteEntry
// after
w.WriteHeader(&archive.Header{Name: "a", PayloadSize: 100})
if _, err := w.Write(buf[:100]); err != nil { return err }
w.WriteHeader(next) Defensive patterns
Strategy: validation
Validate before calling
// track payload bytes per entry before starting the next
written := int64(0)
declared := hdr.HeaderSize + hdr.PayloadSize
// ... accumulate written via Write returns ...
if written != declared { return fmt.Errorf("entry %q: wrote %d of %d bytes", hdr.Name, written, declared) } Try / catch
if err := w.WriteHeader(next); err != nil {
if errors.Is(err, archive.ErrIncompleteEntry) {
return fmt.Errorf("previous entry under-written by %d bytes", prevDeclared-prevWritten)
}
return err
} Prevention
- Always write exactly HeaderSize+PayloadSize bytes; pad short payloads rather than abandoning entries.
- Accumulate the int returned by Write and compare against the declared total after each entry.
- Call Close and check its error — ErrIncompleteEntry at Close is the last chance to detect an unfinished entry.
- Buffer the payload first so the declared size in WriteHeader is exact.
When it happens
Trigger: Writer.WriteHeader(hdr) called while a.header != nil and a.remaining > 0 (previous entry under-written). Writer.Close() called with an open entry and remaining > 0 — i.e. you wrote fewer payload bytes than declared in the Header.
Common situations: Declaring PayloadSize larger than the bytes actually buffered/produced (e.g. payload computed lazily and error path skipped the remaining writes); early return from an error branch after WriteHeader but before finishing Write; a loop that stops writing on a non-fatal condition; forgetting that a Write call that returned ErrWriteTooLong may have left remaining > 0.
Related errors
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/9837a0a88337148f.
Report an issue: GitHub.