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
- Inspect the file content (cat <db>-txid); it should contain a single zero-padded TXID like 0000000000000042
- If invalid, delete the sidecar file — ReadTXIDFile treats a missing file as first-run and litestream will re-derive state via restore/sync
- Re-restore the database from the replica to rebuild consistent local state, or use 'litestream reset' to clear corrupted local LTX state
- 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
- Never write to '<db>-txid' from scripts or editors
- Exclude '*-txid' files from log redirections and templating
- After restoring from backups, validate sidecar contents before starting
- Use 'litestream reset' rather than hand-editing state files
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
- invalid replica, checksum mismatch
- ltx file corrupted
- too many arguments
- failed to format response: %w
- database config #%d: 'watch' can only be enabled with a dire
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/82c01e068b6b3949.
Report an issue: GitHub.