{"record":{"id":"0bec3f1822bc83bc","repo":"benbjohnson/litestream","slug":"encode-ltx-snapshot-header-w","errorCode":null,"errorMessage":"encode ltx snapshot header: %w","messagePattern":"encode ltx snapshot header: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":2880,"sourceCode":"\t\tenc, err := ltx.NewEncoder(pw)\n\t\tif err != nil {\n\t\t\tpw.CloseWithError(fmt.Errorf(\"new ltx encoder: %w\", err))\n\t\t\treturn\n\t\t}\n\t\tif err := enc.EncodeHeader(ltx.Header{\n\t\t\tVersion:   ltx.Version,\n\t\t\tFlags:     ltx.HeaderFlagNoChecksum,\n\t\t\tPageSize:  uint32(pos.pageSize),\n\t\t\tCommit:    commit,\n\t\t\tMinTXID:   1,\n\t\t\tMaxTXID:   pos.pos.TXID,\n\t\t\tTimestamp: time.Now().UnixMilli(),\n\t\t\tWALOffset: walOffset,\n\t\t\tWALSize:   walSize,\n\t\t\tWALSalt1:  rd.salt1,\n\t\t\tWALSalt2:  rd.salt2,\n\t\t}); err != nil {\n\t\t\tpw.CloseWithError(fmt.Errorf(\"encode ltx snapshot header: %w\", err))\n\t\t\treturn\n\t\t}\n\n\t\tif err := db.writeLTXFromDB(ctx, enc, walFile, commit, pageMap); err != nil {\n\t\t\tpw.CloseWithError(fmt.Errorf(\"write snapshot ltx: %w\", err))\n\t\t\treturn\n\t\t}\n\n\t\tif err := enc.Close(); err != nil {\n\t\t\tpw.CloseWithError(fmt.Errorf(\"close ltx snapshot encoder: %w\", err))\n\t\t\treturn\n\t\t}\n\t\t_ = pw.Close()\n\t}()\n\n\treturn &snapshotReadCloser{PipeReader: pr, pos: pos}, nil\n}\n","sourceCodeStart":2862,"sourceCodeEnd":2898,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L2862-L2898","documentation":"Wraps a failure to encode the LTX snapshot header (version, page size, commit, WAL offset/size, salts, timestamp) into the snapshot stream. Encoding writes bytes through the pipe, so failures mean the pipe consumer has closed/cancelled or the header fields were rejected as invalid by the encoder. It aborts the entire snapshot stream via pw.CloseWithError.","triggerScenarios":"enc.EncodeHeader(ltx.Header{...}) fails during snapshot generation: pipe reader closed early, context-cancelled consumer, or an invalid header field (e.g. zero/invalid PageSize because pageSize was not initialized).","commonSituations":"Consumer stops reading on an earlier error leaving the producer to fail on the next write; restore timeout elapsing mid-header; a pageSize of 0 slipping through due to a racing database initialization.","solutions":["Check the consumer for an earlier error or premature close; the root cause is usually on the reading side","Ensure pageSize/commit values are initialized before starting a snapshot (the caller already guards pageSize==0)","Retry the snapshot with a stable, unclosed reader and sufficient timeout","If header values look invalid, verify the database was opened and initialized before replication"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify db initialized (page size set) before snapshot\nif st := db.SyncStatus(); st == dbStatusOffline { return errors.New(\"db not initialized\") }","typeGuard":null,"tryCatchPattern":"err := streamSnapshot(ctx, db)\nif err != nil && strings.Contains(err.Error(), \"encode ltx snapshot header\") {\n    // almost always a consumer-side early close/cancel; inspect consumer first\n    return fmt.Errorf(\"snapshot consumer aborted: %w\", err)\n}","preventionTips":["Keep the pipe consumer reading until EOF","Open and initialize the database before starting replication","Avoid mid-stream cancellation; cancel only with intent to abort","Check the first error on the pipe — later header/write errors are secondary"],"tags":["go","ltx","pipe","encoder","snapshot"],"backgroundTag":"broken-pipe","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}