{"record":{"id":"25e46c3d879e6427","repo":"benbjohnson/litestream","slug":"open-buffer-file-w","errorCode":null,"errorMessage":"open buffer file: %w","messagePattern":"open buffer file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vfs.go","lineNumber":2199,"sourceCode":"func (f *VFSFile) initWriteBuffer() error {\n\tf.mu.Lock()\n\tdefer f.mu.Unlock()\n\treturn f.initWriteBufferWithLock()\n}\n\n// initWriteBufferWithLock initializes the write buffer file for durability.\n// Any existing buffer content is discarded since unsync'd changes are lost on restart.\n// Caller must hold f.mu.\nfunc (f *VFSFile) initWriteBufferWithLock() error {\n\t// Ensure parent directory exists\n\tif err := os.MkdirAll(filepath.Dir(f.bufferPath), 0755); err != nil {\n\t\treturn fmt.Errorf(\"create buffer directory: %w\", err)\n\t}\n\n\t// Open or create buffer file, truncating any existing content\n\tfile, err := os.OpenFile(f.bufferPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open buffer file: %w\", err)\n\t}\n\tf.bufferFile = file\n\tf.bufferNextOff = 0\n\n\treturn nil\n}\n\n// writeToBuffer writes a dirty page to the write buffer for durability.\n// If the page already exists in the buffer, it overwrites at the same offset.\n// Otherwise, it appends to the end of the file.\n// Must be called with f.mu held.\nfunc (f *VFSFile) writeToBuffer(pgno uint32, data []byte) error {\n\tvar writeOffset int64\n\tif existingOff, ok := f.dirty[pgno]; ok {\n\t\t// Page already exists - overwrite at same offset\n\t\twriteOffset = existingOff\n\t} else {\n\t\t// New page - append to end of file","sourceCodeStart":2181,"sourceCodeEnd":2217,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L2181-L2217","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before: buffer file created by root, service now runs as 'app'\nls -l /var/tmp/litestream/buffers/app.db.buffer  # -rw-r--r-- root root\n// after\nsudo chown app:app /var/tmp/litestream/buffers/app.db.buffer","handlingStrategy":"validation","validationCode":"// as the service user, verify the buffer path is openable\nif f, err := os.OpenFile(bufferPath, os.O_RDWR|os.O_CREATE, 0o644); err != nil {\n    return fmt.Errorf(\"buffer file not writable: %w\", err)\n} else { f.Close() }","typeGuard":null,"tryCatchPattern":"if err := db.Open(ctx); err != nil {\n    if strings.Contains(err.Error(), \"open buffer file\") && errors.Is(err, fs.ErrPermission) {\n        return fmt.Errorf(\"chown/chmod buffer file or fix run-user: %w\", err)\n    }\n    return err\n}","preventionTips":["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"],"tags":["go","filesystem","permissions","file-open"],"backgroundTag":"file-open-failed","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}