{"record":{"id":"d0b1d04909f42c55","repo":"benbjohnson/litestream","slug":"extract-timestamp-from-ltx-header-w-d0b1d0","errorCode":null,"errorMessage":"extract timestamp from LTX header: %w","messagePattern":"extract timestamp from LTX header: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gs/replica_client.go","lineNumber":155,"sourceCode":"\treturn newLTXFileIterator(c.bkt.Objects(ctx, &storage.Query{Prefix: prefix}), c, level), nil\n}\n\n// WriteLTXFile writes an LTX file from rd to a remote path.\nfunc (c *ReplicaClient) WriteLTXFile(ctx context.Context, level int, minTXID, maxTXID ltx.TXID, rd io.Reader) (info *ltx.FileInfo, err error) {\n\tif err := c.Init(ctx); err != nil {\n\t\treturn info, err\n\t}\n\n\tkey := litestream.LTXFilePath(c.Path, level, minTXID, maxTXID)\n\n\t// Use TeeReader to peek at LTX header while preserving data for upload\n\tvar buf bytes.Buffer\n\tteeReader := io.TeeReader(rd, &buf)\n\n\t// Extract timestamp from LTX header\n\thdr, _, err := ltx.PeekHeader(teeReader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"extract timestamp from LTX header: %w\", err)\n\t}\n\ttimestamp := time.UnixMilli(hdr.Timestamp).UTC()\n\n\t// Combine buffered data with rest of reader\n\tfullReader := io.MultiReader(&buf, rd)\n\n\tw := c.bkt.Object(key).NewWriter(ctx)\n\tdefer w.Close()\n\n\t// Store timestamp in GCS metadata for accurate timestamp retrieval\n\tw.Metadata = map[string]string{\n\t\tMetadataKeyTimestamp: timestamp.Format(time.RFC3339Nano),\n\t}\n\n\tn, err := io.Copy(w, fullReader)\n\tif err != nil {\n\t\treturn info, err\n\t} else if err := w.Close(); err != nil {","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/gs/replica_client.go#L137-L173","documentation":"WriteLTXFile() peeks at the LTX file header via ltx.PeekHeader to extract the transaction timestamp for GCS object metadata/custom time, and this header parse failed. The data may be corrupt, truncated, or not a valid LTX file. The write is aborted before uploading.","triggerScenarios":"Calling WriteLTXFile() with a reader whose first bytes are not a valid LTX header — truncated LTX file, corrupted file from a failed prior write, zero-length input, or a non-LTX file passed by mistake.","commonSituations":"Disk corruption or partial copy of the local LTX file before upload; interrupted litestream run leaving a truncated WAL frame dump; mixing replica directories from different litestream versions; manually crafted/planted files in the replica path.","solutions":["Inspect the wrapped cause to see the exact LTX parse failure (magic mismatch, checksum, truncation)","Verify the local LTX source file is complete and uncorrupted; re-generate it via a fresh litestream replicate run","Use `litestream ltx -level <level>` to inspect the offending LTX files","Run `litestream reset` for the database to clear corrupted local LTX state","Ensure the reader passed to WriteLTXFile actually streams a full LTX file (not WAL or partial data)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"hdr, _, err := ltx.PeekHeader(file)\nif err != nil {\n    return fmt.Errorf(\"source file is not a valid LTX file: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if _, err := rc.WriteLTXFile(ctx, level, minTXID, maxTXID, rd); err != nil {\n    if strings.Contains(err.Error(), \"extract timestamp from LTX header\") {\n        // source LTX corrupt/truncated — reset local state\n    }\n    return err\n}","preventionTips":["Run `litestream ltx` periodically to verify replica LTX integrity","Use `litestream reset` when local LTX state is suspected corrupt","Ensure clean shutdowns; investigate hosts with disk errors","Never hand-edit or partially copy files inside the replica path"],"tags":["ltx","corruption","gcs","upload"],"backgroundTag":"checksum-mismatch","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}