{"record":{"id":"8b46f7f38b39815d","repo":"nats-io/nats-server","slug":"errwritetoolong","errorCode":"ErrWriteTooLong","errorMessage":"archive: write exceeds declared entry size","messagePattern":"archive: write exceeds declared entry size","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/archive/archive.go","lineNumber":35,"sourceCode":"\t\"bufio\"\n\t\"encoding/binary\"\n\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","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/archive/archive.go#L17-L53","documentation":"ErrWriteTooLong means a single Writer.Write call delivered more bytes than the current entry's declared payload size (HeaderSize+PayloadSize). The Writer writes only the bytes that fit, discards the excess logically, and returns n (bytes accepted) plus this error; the archive format has no way to enlarge a declared size mid-entry.","triggerScenarios":"Writer.Write(p) where len(p) > a.remaining: the entry was declared with a size smaller than the data being pushed, e.g. WriteHeader said PayloadSize=10 but Write sent 100 bytes. Repeated oversized Writes keep failing until the entry is complete.","commonSituations":"Computing the header size before the payload is fully known (streaming a body larger than estimated); forgetting HeaderSize contributes to the payload total; an io.Copy from a source bigger than declared; passing the Writer to code that writes unbounded amounts (e.g. logging libraries).","solutions":["Declare the correct size: buffer the payload first and set PayloadSize (plus HeaderSize) to its actual length before WriteHeader.","Split oversized data across multiple entries or chunk it so each entry's declared size covers all its bytes.","Handle the (int, error) return: on ErrWriteTooLong the excess was dropped — don't retry with the same buffer; re-plan the entry.","Pre-size the entry by writing the payload to a temp buffer/io.Pipe first to learn its length."],"exampleFix":"// before\nw.WriteHeader(&archive.Header{Name: \"x\", PayloadSize: int64(len(hdrBytes))}) // forgot body\nw.Write(append(hdrBytes, body...)) // ErrWriteTooLong\n// after\npayload := append(hdrBytes, body...)\nw.WriteHeader(&archive.Header{Name: \"x\", HeaderSize: int64(len(hdrBytes)), PayloadSize: int64(len(body))})\nw.Write(payload)","handlingStrategy":"validation","validationCode":"// ensure declared size matches data before WriteHeader\ndeclared := int64(len(data))\nif declared != hdr.HeaderSize+hdr.PayloadSize {\n    hdr.HeaderSize, hdr.PayloadSize = 0, declared\n}","typeGuard":null,"tryCatchPattern":"n, err := w.Write(p)\nif errors.Is(err, archive.ErrWriteTooLong) {\n    return fmt.Errorf(\"dropped %d excess bytes: declared %d, got %d\", len(p)-n, declared, len(p))\n}","preventionTips":["Compute the payload length before WriteHeader; never guess or pre-declare sizes for streaming sources.","Remember the entry's total size is HeaderSize + PayloadSize combined.","Check both the byte count and error from Write; oversized bytes are silently truncated from the archive.","Chunk large payloads into multiple entries with their own (correct) sizes."],"tags":["go","archive","writer","size-mismatch"],"backgroundTag":"write-exceeds-declared-size","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}