{"record":{"id":"fcd386da4525a333","repo":"benbjohnson/litestream","slug":"cannot-delete-vfs-file","errorCode":null,"errorMessage":"cannot delete vfs file","messagePattern":"cannot delete vfs file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vfs.go","lineNumber":314,"sourceCode":"\tcfg := GetVFSConfig(name)\n\turiCfg, err := ParseVFSURIConfig(uriParameters)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn MergeVFSConfig(cfg, uriCfg), nil\n}\n\nfunc (vfs *VFS) Delete(name string, dirSync bool) error {\n\tslog.Debug(\"deleting file\", \"name\", name, \"dirSync\", dirSync)\n\terr := vfs.deleteTempFile(name)\n\tif err == nil {\n\t\treturn nil\n\t}\n\tif errors.Is(err, os.ErrNotExist) {\n\t\treturn nil\n\t}\n\tif errors.Is(err, errTempFileNotFound) {\n\t\treturn fmt.Errorf(\"cannot delete vfs file\")\n\t}\n\treturn err\n}\n\nfunc (vfs *VFS) Access(name string, flag sqlite3vfs.AccessFlag) (bool, error) {\n\tslog.Debug(\"accessing file\", \"name\", name, \"flag\", flag)\n\n\tif strings.HasSuffix(name, \"-wal\") {\n\t\treturn vfs.accessWAL(name, flag)\n\t}\n\tif vfs.isTempFileName(name) {\n\t\treturn vfs.accessTempFile(name, flag)\n\t}\n\treturn false, nil\n}\n\nfunc (vfs *VFS) accessWAL(name string, flag sqlite3vfs.AccessFlag) (bool, error) {\n\treturn false, nil","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L296-L332","documentation":"The VFS Delete method (xDelete) was asked to remove a file. When deleteTempFile reports that the name is not a tracked temp file (errTempFileNotFound), the VFS cannot delete it and returns this opaque 'cannot delete vfs file' error. It is intentionally returned instead of success because the file is neither a real file nor a temp file the VFS knows about, so honoring the delete is impossible.","triggerScenarios":"SQLite calls xDelete for a name that is not registered in the VFS temp-file map and does not exist on disk — e.g. deleting a main-database alias, a journal whose temp file was already dropped from the registry, or an arbitrary path passed to xDelete after a process restart lost the in-memory tracking.","commonSituations":"Application deletes a temp/journal file after the VFS registry was reset or the connection pool cycled; TestVFS_TempFileDeleteOnClose-style flows where DeleteOnClose already removed the file and un-tracked it before SQLite issues xDelete; calling Delete on a name that was never opened through this VFS instance.","solutions":["Only call Delete (via SQLite) for files that were previously opened through the same VFS instance and are still tracked.","Check that the file name is a temp-file style name matching what openTempFile produced (base + '-' + fnv64 hash); if you delete manually, delete the actual temp path.","If the registry was lost (restart), drop the file directly on disk with os.Remove instead of going through the VFS.","Upgrade/verify VFS version: newer versions may treat untracked-but-nonexistent deletes as no-ops."],"exampleFix":"// before\ndb.Exec(\"DELETE FROM sqlite_master\") // triggers xDelete on untracked journal names\n\n// after\n// ensure the VFS instance that opened the file is the same one handling deletes,\n// or remove the underlying temp file directly:\nos.Remove(tempPathFor(name))","handlingStrategy":"try-catch","validationCode":"// before deleting, confirm the VFS actually tracks the file\nif !vfs.IsTempFileName(name) && !fileExists(name) { skipDelete() }","typeGuard":null,"tryCatchPattern":"if err := sqlite delete...; err != nil && strings.Contains(err.Error(), \"cannot delete vfs file\") {\n    // file untracked; optionally os.Remove the underlying temp path\n}","preventionTips":["Keep a single long-lived VFS instance for the process lifetime.","Avoid manual deletes of SQLite journal/temp names.","Don't rely on Delete for files already removed via DeleteOnClose.","Log file names with errors to spot untracked-name bugs early."],"tags":["go","vfs","file-delete","sqlite"],"backgroundTag":"file-not-found","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}