benbjohnson/litestream · error

create temp dir for write buffer: %w

Error message

create temp dir for write buffer: %w

What it means

In openMainDB, when no explicit bufferPath is configured, Litestream calls vfs.ensureTempDir() to obtain (or create) a temporary directory used to buffer writes before they are staged for upload. This error wraps any failure of that directory creation. Litestream throws it because the write buffer requires local disk space and a writable directory to operate.

Source

Thrown at vfs.go:236

	if writeEnabled {
		f.writeEnabled = true
		f.dirty = make(map[uint32]int64)
		f.syncInterval = syncInterval
		if f.syncInterval == 0 {
			f.syncInterval = DefaultSyncInterval
		}

		writeSeq := atomic.AddUint64(&vfs.writeSeq, 1)
		if bufferPath != "" {
			if writeSeq == 1 {
				f.bufferPath = bufferPath
			} else {
				f.bufferPath = bufferPath + "." + strconv.FormatUint(writeSeq, 10)
			}
		} else {
			dir, err := vfs.ensureTempDir()
			if err != nil {
				return nil, 0, fmt.Errorf("create temp dir for write buffer: %w", err)
			}
			f.bufferPath = filepath.Join(dir, "write-buffer-"+strconv.FormatUint(writeSeq, 10))
		}

		// Initialize compaction if enabled
		if vfs.CompactionEnabled {
			f.compactor = NewCompactor(client, f.logger)
		}
	}

	// Initialize hydration support if enabled
	if hydrationEnabled {
		if hydrationPath != "" {
			f.hydrationPath = hydrationPath
			f.hydrationPersistent = true
		} else {
			dir, err := vfs.ensureTempDir()
			if err != nil {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Point TMPDIR (or os.TempDir's source) at a writable directory before opening the connection.
  2. Configure an explicit buffer path in the VFS config so Litestream skips the temp-dir lookup and uses your own writable location.
  3. Mount a writable tmpfs/emptyDir volume at /tmp in containers and ensure the process user owns it.
  4. Check disk space and permissions (ls -ld $TMPDIR; df -h) on the target filesystem.

Example fix

// before
// TMPDIR=/nonexistent, container fs read-only
db, err := sql.Open("sqlite", "file:app.db?vfs=litestream&replica_url=s3://bucket/app.db")

// after
os.Setenv("TMPDIR", "/var/tmp/app") // writable volume
db, err := sql.Open("sqlite", "file:app.db?vfs=litestream&replica_url=s3://bucket/app.db")
Defensive patterns

Strategy: validation

Validate before calling

tmp := os.TempDir()
if fi, err := os.Stat(tmp); err != nil || !fi.IsDir() {
    return fmt.Errorf("temp dir %q unusable: %w", tmp, err)
}
probe, err := os.CreateTemp(tmp, "litestream-probe-*")
if err != nil { return err }
probe.Remove()

Try / catch

db, err := sql.Open("sqlite", dsn)
if err != nil && strings.Contains(err.Error(), "create temp dir for write buffer") {
    os.Setenv("TMPDIR", "/var/tmp/app")
    return reopenDB(dsn)
}

Prevention

When it happens

Trigger: Opening a VFS database when the temp directory cannot be created or found: os.TempDir() points to a non-writable path, TMPDIR is set to a nonexistent or permission-denied directory, or the filesystem holding /tmp is full/read-only.

Common situations: Containers with read-only root filesystems and no tmpfs mounted at /tmp; serverless environments with restricted /tmp; running as a non-root user with TMPDIR pointing at another user's directory; disk-full conditions on small instances.

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