benbjohnson/litestream · error

create parent directory: %w

Error message

create parent directory: %w

What it means

Before restoring, DB.EnsureExists(ctx) creates the parent directory of db.Path() with os.MkdirAll(dir, 0o750). If that fails, it wraps the error as "create parent directory". Typical causes are filesystem permission denied, read-only mounts, or an invalid path component.

Source

Thrown at db.go:749

// database file does not exist. If no backup is available, it returns nil and
// a fresh database will be created on Open(). Must be called before Open().
func (db *DB) EnsureExists(ctx context.Context) error {
	if db.Replica == nil {
		return fmt.Errorf("no replica configured")
	}
	if db.Replica.Client == nil {
		return fmt.Errorf("no replica client configured")
	}

	if _, err := os.Stat(db.Path()); err == nil {
		return nil
	} else if !os.IsNotExist(err) {
		return fmt.Errorf("stat database: %w", err)
	}

	if dir := filepath.Dir(db.Path()); dir != "." {
		if err := os.MkdirAll(dir, 0o750); err != nil {
			return fmt.Errorf("create parent directory: %w", err)
		}
	}

	opt := NewRestoreOptions()
	opt.OutputPath = db.Path()
	opt.IntegrityCheck = IntegrityCheckQuick

	if err := db.Replica.Restore(ctx, opt); err != nil {
		if errors.Is(err, ErrTxNotAvailable) || errors.Is(err, ErrNoSnapshots) {
			db.Logger.Debug("no backup found, will create fresh database")
			return nil
		}
		return fmt.Errorf("restore from backup: %w", err)
	}

	db.Logger.Info("database restored from backup", "path", db.Path())
	return nil
}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Read the wrapped errno: EACCES -> fix permissions, EROFS -> mount writable volume, ENOTDIR -> remove/fix the conflicting file.
  2. chown/chmod the data directory for the litestream process user (or run the container with the right UID).
  3. Ensure the volume containing the db path is writable and mounted.
  4. Pre-create the parent directory in deployment (init container/entrypoint) so MkdirAll is a no-op.
Defensive patterns

Strategy: validation

Validate before calling

dir := filepath.Dir(db.Path())
if dir != "." {
    if err := os.MkdirAll(dir, 0o750); err != nil {
        return fmt.Errorf("preflight mkdir failed: %w", err)
    }
}

Try / catch

if err := db.EnsureExists(ctx); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.EACCES) {
        log.Error("mkdir permission denied", "path", pe.Path)
    }
    return err
}

Prevention

When it happens

Trigger: os.MkdirAll failing while creating the db's parent directory: parent not writable by the litestream user, read-only filesystem/volume, ENAMETOOLONG, or a non-directory existing at some path component.

Common situations: Container running as non-root with the data volume owned by root; read-only rootfs with the db path on /; db path configured under a directory that exists as a regular file; too-long paths from deeply nested $PID-expanded config paths.

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/3f68c510acedb5e2. Report an issue: GitHub.