benbjohnson/litestream · error

write txid: %w

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.

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)

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.