benbjohnson/litestream · error
create txid temp file: %w
Error message
create txid temp file: %w
What it means
WriteTXIDFile wraps os.Create failure when creating the temporary file (<txid-path>.tmp) used to atomically persist the restored database's last TXID next to the output. The wrapped cause carries the OS-level reason (permissions, missing directory, disk full).
Source
Thrown at replica.go:1726
}
return next.CreatedAt.Before(curr.CreatedAt)
}
// TXIDPath returns the path to the TXID sidecar file for the given database path.
// Uses -txid suffix to match SQLite's naming convention for associated files (-wal, -shm).
func TXIDPath(outputPath string) string {
return outputPath + "-txid"
}
// WriteTXIDFile atomically writes a TXID to a sidecar file at <outputPath>-txid.
// Uses temp-file + fsync + rename for crash safety.
func WriteTXIDFile(outputPath string, txid ltx.TXID) error {
txidPath := TXIDPath(outputPath)
tmpPath := txidPath + ".tmp"
f, err := os.Create(tmpPath)
if err != nil {
return fmt.Errorf("create txid temp file: %w", err)
}
defer f.Close()
defer os.Remove(tmpPath)
if _, err := fmt.Fprintln(f, txid); err != nil {
return fmt.Errorf("write txid: %w", err)
}
if err := f.Sync(); err != nil {
return fmt.Errorf("sync txid file: %w", err)
}
if err := f.Close(); err != nil {
return fmt.Errorf("close txid file: %w", err)
}
if err := os.Rename(tmpPath, txidPath); err != nil {
return fmt.Errorf("rename txid file: %w", err)View on GitHub (pinned to 4ed7a308f6)
Solutions
- Ensure the restore output directory exists and is writable by the litestream process user.
- Check available disk space (df -h) and inode/quota limits.
- Restore to a different path, then move the files into place.
- In containers, mount the target volume with write permissions.
Example fix
// before $ litestream restore -o /readonly/db.sqlite db // error: create txid temp file: open /readonly/db.sqlite.txid.tmp: permission denied // after $ mkdir -p /data && chown litestream /data $ litestream restore -o /data/db.sqlite db
Defensive patterns
Strategy: validation
Validate before calling
// Go: verify the output directory is writable before restore
dir := filepath.Dir(outputPath)
if info, err := os.Stat(dir); err != nil || !info.IsDir() {
return fmt.Errorf("output dir missing: %s", dir)
}
probe, err := os.CreateTemp(dir, ".litestream-probe-*")
if err != nil {
return fmt.Errorf("output dir not writable: %w", err)
}
probe.Close(); os.Remove(probe.Name()) Try / catch
if err := WriteTXIDFile(path, txid); err != nil {
var perr *fs.PathError
if errors.As(err, &perr) {
// perr.Err: EACCES/ENOENT/ENOSPC -> fix dir permissions or free space
}
return err
} Prevention
- Create and chmod the restore output directory before running restore.
- Run restores as a user with write access to the target volume.
- In containers, mount the target path read-write.
- Keep enough free disk for the DB plus its .txid sidecar.
When it happens
Trigger: Restore completing to an output path whose parent directory does not exist, is read-only, or where creating `<output>.txid.tmp` fails (EACCES, ENOSPC, read-only filesystem, sandboxed container FS).
Common situations: Restore target inside a non-writable container path; SELinux/AppArmor restrictions; output directory created only after restore started; full disk during DR recovery.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- write txid: %w
- cannot access output path: %w
- cannot restore, output path is a directory: %s
- cannot restore, output path already exists and is not empty:
- cannot access SQLite sidecar path: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/60fefcae51486801.
Report an issue: GitHub.