benbjohnson/litestream · error

recreate L0 directory: %w

Error message

recreate L0 directory: %w

What it means

After clearing the L0 directory, checkDatabaseBehindReplica recreates it with internal.MkdirAll using the configured directory mode. This error wraps a failure to recreate the level-0 LTX directory. Without it, Litestream cannot write the fetched LTX file locally.

Source

Thrown at db.go:1620

	}

	// Check if database is behind replica
	if dbPos.TXID >= replicaInfo.MaxTXID {
		return nil // Database is ahead or equal
	}

	db.Logger.Info("detected database behind replica",
		"db_txid", dbPos.TXID,
		"replica_txid", replicaInfo.MaxTXID)

	// Clear local L0 files
	l0Dir := db.LTXLevelDir(0)
	if err := os.RemoveAll(l0Dir); err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("remove L0 directory: %w", err)
	}
	db.invalidatePosCache()
	if err := internal.MkdirAll(l0Dir, db.dirInfo); err != nil {
		return fmt.Errorf("recreate L0 directory: %w", err)
	}

	// Fetch latest L0 LTX file from replica
	minTXID, maxTXID := replicaInfo.MinTXID, replicaInfo.MaxTXID
	reader, err := db.Replica.Client.OpenLTXFile(ctx, 0, minTXID, maxTXID, 0, 0)
	if err != nil {
		return fmt.Errorf("open remote L0 file: %w", err)
	}
	defer func() { _ = reader.Close() }()

	// Write to temp file and atomically rename
	localPath := db.LTXPath(0, minTXID, maxTXID)
	tmpPath := localPath + ".tmp"

	tmpFile, err := os.Create(tmpPath)
	if err != nil {
		return fmt.Errorf("create temp L0 file: %w", err)
	}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Ensure the database's parent directory exists and is writable by the litestream user (mkdir -p, chown).
  2. Check disk space (df -h) and quota on the data volume.
  3. Check SELinux/AppAudit denial logs (ausearch -m avc) if permissions look correct.
  4. Compare with how litestream creates the dir at startup — if startup works but this fails, another process is interfering with the LTX directory.

Example fix

// before: directory missing at runtime
// after: ensure data dir exists before starting litestream
$ install -d -o litestream -g litestream /var/lib/db
$ systemctl start litestream
Defensive patterns

Strategy: validation

Validate before calling

// Ensure parent dir exists and is writable before litestream starts
if err := os.MkdirAll(dbDir, 0o755); err != nil {
    log.Fatalf("cannot prepare db dir: %v", err)
}

Type guard

null

Try / catch

if err := internal.MkdirAll(l0Dir, db.dirInfo); err != nil {
    return fmt.Errorf("recreate L0 directory: %w", err)
} // on EACCES/ENOENT, fix ownership/existence of the parent dir and retry

Prevention

When it happens

Trigger: Immediately after a successful RemoveAll of the L0 dir, internal.MkdirAll(l0Dir, db.dirInfo) fails — parent directory missing/unwritable, or the directory was recreated by another process with restrictive permissions between the two calls.

Common situations: The database directory itself was deleted or moved while litestream runs; parent dir permissions changed (mkdir-permission-denied); disk full preventing directory creation; SELinux/AppArmor blocking mkdir in the data path.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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