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

  1. Inspect the wrapped cause to see the exact LTX parse failure (magic mismatch, checksum, truncation)
  2. Verify the local LTX source file is complete and uncorrupted; re-generate it via a fresh litestream replicate run
  3. Use `litestream ltx -level <level>` to inspect the offending LTX files
  4. Run `litestream reset` for the database to clear corrupted local LTX state
  5. 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

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


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/d0b1d04909f42c55. Report an issue: GitHub.