nats-io/nats-server · error

ErrNegativeEntrySize

ErrNegativeEntrySize

Error message

archive: negative entry size

What it means

ErrNegativeEntrySize is returned by the archive writer's WriteHeader when a Header describes negative sizes. An archive entry cannot have a negative header or payload byte count, so such a header is rejected before anything is written. It also guards against signed integer overflow when HeaderSize and PayloadSize are summed.

Source

Thrown at server/archive/archive.go:37

	"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    uint64
}

func (h *Header) clone() *Header {
	if h == nil {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Fix the caller so HeaderSize and PayloadSize are computed as non-negative values (check len() results before assignment)
  2. Validate header fields before calling WriteHeader and reject negative values upstream
  3. If sizes come from parsed input, clamp or reject values that don't fit in int64

Example fix

// before
hdr.PayloadSize := int64(len(body) - offset) // offset > len(body) yields negative
// after
if offset > int64(len(body)) {
    return fmt.Errorf("invalid offset %d", offset)
}
hdr.PayloadSize = int64(len(body)) - offset
Defensive patterns

Strategy: validation

Validate before calling

func validHeader(hdr *archive.Header) bool {
    return hdr != nil && hdr.HeaderSize >= 0 && hdr.PayloadSize >= 0 &&
        hdr.HeaderSize+hdr.PayloadSize >= 0
}
if !validHeader(hdr) {
    return fmt.Errorf("invalid entry header sizes")
}
err := aw.WriteHeader(hdr)

Try / catch

n, err := aw.WriteHeader(hdr)
if errors.Is(err, archive.ErrNegativeEntrySize) {
    log.Fatalf("entry header has negative size: %v", err)
}

Prevention

When it happens

Trigger: Calling WriteHeader with hdr.HeaderSize < 0, hdr.PayloadSize < 0, or with values whose sum (HeaderSize+PayloadSize) overflows to negative on 64-bit ints.

Common situations: Bugs in code computing entry sizes from other values (e.g. subtracting lengths), or unmarshaling a header from corrupt/hostile bytes producing negative sizes.

Related errors


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