benbjohnson/litestream · error

write txid

Error message

write txid: %w

What it means

WriteTXIDFile wraps a failure writing the TXID line to the temporary file via fmt.Fprintln. This is rare (usually disk-full ENOSPC or an I/O error on the underlying file handle) but the TXID marker could not be persisted, so restore cannot safely record the last applied transaction.

Solutions

  1. Free disk space or expand the volume, then re-run the restore.
  2. Check dmesg/journal for I/O errors on the target device and replace failing media.
  3. Restore to a healthy local path and sync to the final location afterwards.
  4. Re-run the restore; the .tmp file is removed on failure so no partial state is left.

Example fix

// before
// error: write txid: write /data/db.sqlite.txid.tmp: no space left on device
$ df -h /data   # 100% used
// after
$ rm /data/old-backups/*  # or expand volume
$ litestream restore -o /data/db.sqlite db
Defensive patterns

Strategy: validation

Validate before calling

// Go: check free space on the target filesystem before restore
var st syscall.Statfs_t
if err := syscall.Statfs(dir, &st); err == nil {
    avail := int64(st.Bavail) * int64(st.Bsize)
    if avail < minRequiredBytes {
        return fmt.Errorf("insufficient space: %d bytes free", avail)
    }
}

Try / catch

if err := WriteTXIDFile(path, txid); err != nil {
    if strings.Contains(err.Error(), "write txid") {
        // almost always ENOSPC or device I/O error: free space / check dmesg, then re-run
    }
    return err
}

Prevention

When it happens

Trigger: Disk filling up mid-write during restore; I/O errors on failing storage; filesystem quota exceeded while writing <output>.txid.tmp.

Common situations: DR recovery on an almost-full volume; network filesystems returning short writes/EIO; container ephemeral storage quota hit during a large restore.

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


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

Appendix: source

Thrown at replica.go:1732

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)
	}

	if err := internal.FsyncDir(filepath.Dir(txidPath)); err != nil {
		return fmt.Errorf("sync txid dir: %w", err)
	}
	return nil

View on GitHub (pinned to 4ed7a308f6)