{"record":{"id":"6fd89eb89178e62b","repo":"nats-io/nats-server","slug":"errnegativeentrysize","errorCode":"ErrNegativeEntrySize","errorMessage":"archive: negative entry size","messagePattern":"archive: negative entry size","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/archive/archive.go","lineNumber":37,"sourceCode":"\t\"errors\"\n\t\"io\"\n)\n\nconst MagicBytes = \"NATSARC1\"\n\n// maxNameLen bounds the entry name length accepted when reading an archive,\n// avoiding an unbounded allocation on corrupt or malicious input. The name is\n// the only variable-length field read directly from the stream.\nconst maxNameLen = 1 << 20\n\nvar (\n\tErrClosed            = errors.New(\"archive: closed\")\n\tErrInvalidArchive    = errors.New(\"archive: invalid archive stream\")\n\tErrIncompleteEntry   = errors.New(\"archive: entry not fully written\")\n\tErrNoActiveEntry     = errors.New(\"archive: no active entry\")\n\tErrWriteTooLong      = errors.New(\"archive: write exceeds declared entry size\")\n\tErrNilHeader         = errors.New(\"archive: nil header\")\n\tErrNegativeEntrySize = errors.New(\"archive: negative entry size\")\n)\n\n// Header describes one archive entry.\n//\n// On the wire each entry is the encoded header fields followed by the payload.\n// HeaderSize and PayloadSize describe how that payload is split (e.g. message\n// headers vs. body); the payload length is their sum and is not stored\n// separately. Sequence is always encoded, with 0 meaning \"unset\".\ntype Header struct {\n\tName        string\n\tHeaderSize  int64\n\tPayloadSize int64\n\tTimestamp   int64\n\tSequence    uint64\n}\n\nfunc (h *Header) clone() *Header {\n\tif h == nil {","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/archive/archive.go#L19-L55","documentation":"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.","triggerScenarios":"Calling WriteHeader with hdr.HeaderSize < 0, hdr.PayloadSize < 0, or with values whose sum (HeaderSize+PayloadSize) overflows to negative on 64-bit ints.","commonSituations":"Bugs in code computing entry sizes from other values (e.g. subtracting lengths), or unmarshaling a header from corrupt/hostile bytes producing negative sizes.","solutions":["Fix the caller so HeaderSize and PayloadSize are computed as non-negative values (check len() results before assignment)","Validate header fields before calling WriteHeader and reject negative values upstream","If sizes come from parsed input, clamp or reject values that don't fit in int64"],"exampleFix":"// before\nhdr.PayloadSize := int64(len(body) - offset) // offset > len(body) yields negative\n// after\nif offset > int64(len(body)) {\n    return fmt.Errorf(\"invalid offset %d\", offset)\n}\nhdr.PayloadSize = int64(len(body)) - offset","handlingStrategy":"validation","validationCode":"func validHeader(hdr *archive.Header) bool {\n    return hdr != nil && hdr.HeaderSize >= 0 && hdr.PayloadSize >= 0 &&\n        hdr.HeaderSize+hdr.PayloadSize >= 0\n}\nif !validHeader(hdr) {\n    return fmt.Errorf(\"invalid entry header sizes\")\n}\nerr := aw.WriteHeader(hdr)","typeGuard":null,"tryCatchPattern":"n, err := aw.WriteHeader(hdr)\nif errors.Is(err, archive.ErrNegativeEntrySize) {\n    log.Fatalf(\"entry header has negative size: %v\", err)\n}","preventionTips":["Compute sizes from len() results that are checked non-negative","Validate all header fields before WriteHeader","Never cast unsigned lengths to signed ints without bounds checks"],"tags":["archive","io","validation","go"],"backgroundTag":"negative-size-header","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}