benbjohnson/litestream · error
extract timestamp from LTX header: %w
Error message
extract timestamp from LTX header: %w
What it means
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.
Source
Thrown at gs/replica_client.go:155
return newLTXFileIterator(c.bkt.Objects(ctx, &storage.Query{Prefix: prefix}), c, level), nil
}
// WriteLTXFile writes an LTX file from rd to a remote path.
func (c *ReplicaClient) WriteLTXFile(ctx context.Context, level int, minTXID, maxTXID ltx.TXID, rd io.Reader) (info *ltx.FileInfo, err error) {
if err := c.Init(ctx); err != nil {
return info, err
}
key := litestream.LTXFilePath(c.Path, level, minTXID, maxTXID)
// Use TeeReader to peek at LTX header while preserving data for upload
var buf bytes.Buffer
teeReader := io.TeeReader(rd, &buf)
// Extract timestamp from LTX header
hdr, _, err := ltx.PeekHeader(teeReader)
if err != nil {
return nil, fmt.Errorf("extract timestamp from LTX header: %w", err)
}
timestamp := time.UnixMilli(hdr.Timestamp).UTC()
// Combine buffered data with rest of reader
fullReader := io.MultiReader(&buf, rd)
w := c.bkt.Object(key).NewWriter(ctx)
defer w.Close()
// Store timestamp in GCS metadata for accurate timestamp retrieval
w.Metadata = map[string]string{
MetadataKeyTimestamp: timestamp.Format(time.RFC3339Nano),
}
n, err := io.Copy(w, fullReader)
if err != nil {
return info, err
} else if err := w.Close(); err != nil {View on GitHub (pinned to 4ed7a308f6)
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)
Defensive patterns
Strategy: validation
Validate before calling
hdr, _, err := ltx.PeekHeader(file)
if err != nil {
return fmt.Errorf("source file is not a valid LTX file: %w", err)
} Try / catch
if _, err := rc.WriteLTXFile(ctx, level, minTXID, maxTXID, rd); err != nil {
if strings.Contains(err.Error(), "extract timestamp from LTX header") {
// source LTX corrupt/truncated — reset local state
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- extract timestamp from LTX header: %w
- extract timestamp from LTX header: %w
- invalid replica, checksum mismatch
- ltx file corrupted
- verify
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/d0b1d04909f42c55.
Report an issue: GitHub.