benbjohnson/litestream · error

parse txid file: %w

Error message

parse txid file: %w

What it means

After reading the sidecar file, ReadTXIDFile parses its trimmed contents with ltx.ParseTXID. This error means the file content is not a valid TXID string. Since the file is written atomically (temp + fsync + rename), invalid content usually indicates manual tampering, truncation by another tool, or a file created by an incompatible version.

Source

Thrown at replica.go:1767

	}
	return nil
}

// ReadTXIDFile reads the TXID from a sidecar file at <outputPath>-txid.
// Returns 0, nil if the file does not exist (first run).
func ReadTXIDFile(outputPath string) (ltx.TXID, error) {
	txidPath := TXIDPath(outputPath)

	data, err := os.ReadFile(txidPath)
	if os.IsNotExist(err) {
		return 0, nil
	} else if err != nil {
		return 0, fmt.Errorf("read txid file: %w", err)
	}

	txid, err := ltx.ParseTXID(strings.TrimSpace(string(data)))
	if err != nil {
		return 0, fmt.Errorf("parse txid file: %w", err)
	}

	return txid, nil
}

// ValidationError represents a single validation issue.
type ValidationError struct {
	Level    int           // compaction level
	Type     string        // "gap", "overlap", or "unsorted"
	Message  string        // human-readable description
	PrevFile *ltx.FileInfo // previous file
	CurrFile *ltx.FileInfo // current file that caused error
}

// ValidateLevel checks LTX files at the given level are sorted and contiguous.
// Returns a slice of validation errors (empty if valid).
func (r *Replica) ValidateLevel(ctx context.Context, level int) ([]ValidationError, error) {
	itr, err := r.Client.LTXFiles(ctx, level, 0, false)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Inspect the file content (cat <db>-txid); it should contain a single zero-padded TXID like 0000000000000042
  2. If invalid, delete the sidecar file — ReadTXIDFile treats a missing file as first-run and litestream will re-derive state via restore/sync
  3. Re-restore the database from the replica to rebuild consistent local state, or use 'litestream reset' to clear corrupted local LTX state
  4. Stop any scripts/tools that write to '<db>-txid' or paths adjacent to the database

Example fix

# before: manually editing the sidecar file
echo "latest" > my.db-txid
# after: let litestream manage it
rm my.db-txid            # first-run semantics: treated as 0
litestream restore -o my.db mydb.db
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile(TXIDPath(outputPath))
if err == nil {
    if _, perr := ltx.ParseTXID(strings.TrimSpace(string(data))); perr != nil {
        // treat as corrupt: remove so ReadTXIDFile returns first-run semantics
        os.Remove(TXIDPath(outputPath))
    }
}

Type guard

func validTXIDFile(path string) bool {
    b, err := os.ReadFile(path)
    if err != nil { return false }
    _, err = ltx.ParseTXID(strings.TrimSpace(string(b)))
    return err == nil
}

Try / catch

txid, err := ReadTXIDFile(outputPath)
if err != nil {
    var parseErr *strconv.ErrSyntax
    if errors.As(err, &parseErr) {
        os.Remove(TXIDPath(outputPath)) // reset to first-run
        txid, err = 0, nil
    }
}

Prevention

When it happens

Trigger: os.ReadFile succeeded on '<outputPath>-txid' but ltx.ParseTXID rejects the trimmed content: empty file, HTML/error text written there by mistake, a truncated partial write from external tooling, or a binary blob in place of the expected textual TXID (e.g. '0000000000000001').

Common situations: A deployment script or health-check accidentally overwrote the -txid file; editor or log redirection wrote garbage into it; disk corruption; mixing outputs from different litestream versions.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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