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 header of the incoming stream to extract the transaction timestamp. If the reader does not begin with a valid LTX header, PeekHeader fails and this error wraps the cause. Because the reader is TeeReader'd, this happens before any bytes are uploaded.
Source
Thrown at oss/replica_client.go:245
return result.Body, nil
}
// WriteLTXFile writes an LTX file to the replica.
// Extracts timestamp from LTX header and stores it in OSS metadata to preserve original creation time.
// Uses multipart upload for large files via the uploader.
func (c *ReplicaClient) WriteLTXFile(ctx context.Context, level int, minTXID, maxTXID ltx.TXID, r io.Reader) (*ltx.FileInfo, error) {
if err := c.Init(ctx); err != nil {
return nil, err
}
// Use TeeReader to peek at LTX header while preserving data for upload
var buf bytes.Buffer
teeReader := io.TeeReader(r, &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
rc := internal.NewReadCounter(io.MultiReader(&buf, r))
filename := ltx.FormatFilename(minTXID, maxTXID)
key := c.ltxPath(level, filename)
// Store timestamp in OSS metadata for accurate timestamp retrieval
metadata := map[string]string{
MetadataKeyTimestamp: timestamp.Format(time.RFC3339Nano),
}
// Use uploader for automatic multipart handling (files >5GB)
result, err := c.uploader.UploadFrom(ctx, &oss.PutObjectRequest{
Bucket: oss.Ptr(c.Bucket),
Key: oss.Ptr(key),View on GitHub (pinned to 4ed7a308f6)
Solutions
- Validate the local LTX file with 'litestream ltx <file>' to confirm header integrity.
- If the local LTX state is corrupted, run 'litestream reset <db>' to clear it and let replication restart.
- Upgrade litestream so the writer and replica client use the same LTX format version.
- If this comes from custom code, ensure you pass the raw LTX stream (never a pre-opened/partially consumed reader).
Example fix
// before
f, _ := os.Open(corruptPath)
info, err := client.WriteLTXFile(ctx, key, metadata, f, size)
// after
if _, _, err := ltx.PeekHeader(f); err != nil {
return fmt.Errorf("local ltx file corrupt, run litestream reset: %w", err)
}
f.Seek(0, io.SeekStart)
info, err := client.WriteLTXFile(ctx, key, metadata, f, size) Defensive patterns
Strategy: validation
Validate before calling
// Verify the stream starts with a valid LTX header before uploading.
if _, _, err := ltx.PeekHeader(reader); err != nil {
return fmt.Errorf("invalid ltx stream: %w", err)
} Prevention
- Never write non-Litestream data into the LTX replica path.
- Keep writer and replica client on the same litestream version to avoid format drift.
- Monitor disk health; corruption of local LTX files surfaces here first.
When it happens
Trigger: Passing a reader to WriteLTXFile whose first bytes are not a valid ltx.Header: truncated WAL-to-LTX conversion output, corrupted file on disk, or a caller (custom code/tests) feeding a non-LTX stream.
Common situations: Disk corruption or partial write of the local LTX file before upload; running a mismatched/older litestream version that produced an incompatible header; third-party tooling writing into 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/f060dfdf852411a2.
Report an issue: GitHub.