benbjohnson/litestream · error

create temp dir: %w

Error message

create temp dir: %w

What it means

ensureTempDir lazily creates the shared temp directory (litestream-vfs-*) once per VFS via sync.Once. This error wraps the failure of os.MkdirTemp, stored as tempDirErr and returned on every subsequent call. It is thrown when the OS refuses or fails to create the directory used for temp files, write buffers, and hydration files.

Source

Thrown at vfs.go:357

func (vfs *VFS) requiresTempFile(flags sqlite3vfs.OpenFlag) bool {
	const tempMask = sqlite3vfs.OpenTempDB |
		sqlite3vfs.OpenTempJournal |
		sqlite3vfs.OpenSubJournal |
		sqlite3vfs.OpenSuperJournal |
		sqlite3vfs.OpenTransientDB |
		sqlite3vfs.OpenMainJournal
	if flags&tempMask != 0 {
		return true
	}
	return flags&sqlite3vfs.OpenDeleteOnClose != 0
}

func (vfs *VFS) ensureTempDir() (string, error) {
	vfs.tempDirOnce.Do(func() {
		dir, err := os.MkdirTemp("", "litestream-vfs-*")
		if err != nil {
			vfs.tempDirErr = fmt.Errorf("create temp dir: %w", err)
			return
		}
		vfs.tempDir = dir
	})
	return vfs.tempDir, vfs.tempDirErr
}

func (vfs *VFS) canonicalTempName(name string) string {
	if name == "" {
		return ""
	}
	name = filepath.Clean(name)
	if name == "." || name == string(filepath.Separator) {
		return ""
	}
	return name
}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Ensure TMPDIR (or /tmp) exists, is writable by the process user, and has free space.
  2. Set explicit paths in the VFS config (hydration path, buffer path) so the shared temp dir is not required for those features.
  3. Check container/sandbox policies (PrivateTmp, seccomp, SELinux) that block mkdir in the temp root.
  4. Restart the process after fixing the environment — the failure is cached in sync.Once for the VFS lifetime.

Example fix

// before
os.Setenv("TMPDIR", "/nonexistent")

// after
os.MkdirAll("/var/lib/app/tmp", 0o755)
os.Setenv("TMPDIR", "/var/lib/app/tmp")
Defensive patterns

Strategy: validation

Validate before calling

dir := os.TempDir()
fi, err := os.Stat(dir)
if err != nil || !fi.IsDir() {
    return fmt.Errorf("TMPDIR %q invalid: %w", dir, err)
}
if err := unix.Access(dir, unix.W_OK); err != nil {
    return fmt.Errorf("TMPDIR %q not writable: %w", dir, err)
}

Try / catch

if _, err := os.Stat(vfs.TempDir()); err != nil {
    // VFS temp dir creation failed permanently (sync.Once cached); recreate the VFS after fixing env
}

Prevention

When it happens

Trigger: Any VFS operation that needs the lazily-created temp dir — opening a main DB with hydration enabled but no hydration path, enabling write buffering without a buffer path, or opening temp/transient files (openTempFile) — when os.MkdirTemp("") fails.

Common situations: TMPDIR unset-to-invalid or pointing to a full read-only filesystem; running as a user without write access to the temp root; chroot/container images lacking /tmp; SELinux/AppArmor denying temp directory creation.

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