benbjohnson/litestream · error
open buffer file: %w
Error message
open buffer file: %w
What it means
After ensuring the parent directory exists, initWriteBufferWithLock opens (and truncates) the write-buffer file with os.OpenFile(O_RDWR|O_CREATE|O_TRUNC). This error wraps that open failure, so the durable write buffer could not be established and the VFS file cannot start accepting writes.
Source
Thrown at vfs.go:2199
func (f *VFSFile) initWriteBuffer() error {
f.mu.Lock()
defer f.mu.Unlock()
return f.initWriteBufferWithLock()
}
// initWriteBufferWithLock initializes the write buffer file for durability.
// Any existing buffer content is discarded since unsync'd changes are lost on restart.
// Caller must hold f.mu.
func (f *VFSFile) initWriteBufferWithLock() error {
// Ensure parent directory exists
if err := os.MkdirAll(filepath.Dir(f.bufferPath), 0755); err != nil {
return fmt.Errorf("create buffer directory: %w", err)
}
// Open or create buffer file, truncating any existing content
file, err := os.OpenFile(f.bufferPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return fmt.Errorf("open buffer file: %w", err)
}
f.bufferFile = file
f.bufferNextOff = 0
return nil
}
// writeToBuffer writes a dirty page to the write buffer for durability.
// If the page already exists in the buffer, it overwrites at the same offset.
// Otherwise, it appends to the end of the file.
// Must be called with f.mu held.
func (f *VFSFile) writeToBuffer(pgno uint32, data []byte) error {
var writeOffset int64
if existingOff, ok := f.dirty[pgno]; ok {
// Page already exists - overwrite at same offset
writeOffset = existingOff
} else {
// New page - append to end of fileView on GitHub (pinned to 4ed7a308f6)
Solutions
- Check the wrapped syscall error: EACCES/EPERM → fix file ownership (chown) or run under the correct user; ENOSPC/quota → free space; EISDIR → remove the misplaced directory at bufferPath.
- If the buffer file exists with wrong ownership from a prior root run, delete or chown it before restart.
- Point bufferPath at a dedicated writable volume and verify with a manual touch as the service user.
- Ensure only one litestream instance uses the buffer path to avoid permission/lock contention.
Example fix
// before: buffer file created by root, service now runs as 'app' ls -l /var/tmp/litestream/buffers/app.db.buffer # -rw-r--r-- root root // after sudo chown app:app /var/tmp/litestream/buffers/app.db.buffer
Defensive patterns
Strategy: validation
Validate before calling
// as the service user, verify the buffer path is openable
if f, err := os.OpenFile(bufferPath, os.O_RDWR|os.O_CREATE, 0o644); err != nil {
return fmt.Errorf("buffer file not writable: %w", err)
} else { f.Close() } Try / catch
if err := db.Open(ctx); err != nil {
if strings.Contains(err.Error(), "open buffer file") && errors.Is(err, fs.ErrPermission) {
return fmt.Errorf("chown/chmod buffer file or fix run-user: %w", err)
}
return err
} Prevention
- Run a startup smoke test that touches the buffer path as the service user
- Keep buffer files owned by the same user across restarts/deployments
- Watch disk quotas on the buffer volume
When it happens
Trigger: os.OpenFile(f.bufferPath, O_RDWR|O_CREATE|O_TRUNC, 0644) fails: directory not writable, file exists but is owned by another user, disk quota exceeded, or path is invalid (e.g. a directory already exists at that name).
Common situations: Previous run created the buffer file as root while the service now runs unprivileged; disk quota exceeded on the buffer volume; stale directory sitting at the buffer file path after a bad migration; encrypted/tmpfs mounts with restrictive modes.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- open persistent hydration file: %w
- create buffer directory: %w
- cannot access output path: %w
- cannot access SQLite sidecar path: %w
- remove existing output path: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/25e46c3d879e6427.
Report an issue: GitHub.