benbjohnson/litestream · warning
temp file not tracked
Error message
temp file not tracked
What it means
errTempFileNotFound is the sentinel error indicating a requested temp file name is not present in the VFS's in-memory temp-file registry. Delete translates it into the opaque 'cannot delete vfs file' error, and the Delete/deleteTempFile path returns it when the name is tracked-format (temp-style name) but no corresponding tracked temp file entry exists.
Source
Thrown at vfs.go:517
}
func openFlagToOSFlag(flag sqlite3vfs.OpenFlag) int {
var v int
if flag&sqlite3vfs.OpenReadWrite != 0 {
v |= os.O_RDWR
} else if flag&sqlite3vfs.OpenReadOnly != 0 {
v |= os.O_RDONLY
}
if flag&sqlite3vfs.OpenCreate != 0 {
v |= os.O_CREATE
}
if flag&sqlite3vfs.OpenExclusive != 0 {
v |= os.O_EXCL
}
return v
}
var errTempFileNotFound = fmt.Errorf("temp file not tracked")
// localTempFile fulfills sqlite3vfs.File solely for SQLite temp & transient files.
// These files stay on the local filesystem and optionally delete themselves
// when SQLite closes them (DeleteOnClose flag).
type localTempFile struct {
f *os.File
deleteOnClose bool
lockType atomic.Int32
onClose func()
}
func newLocalTempFile(f *os.File, deleteOnClose bool, onClose func()) *localTempFile {
return &localTempFile{f: f, deleteOnClose: deleteOnClose, onClose: onClose}
}
func (tf *localTempFile) Close() error {
err := tf.f.Close()
if tf.deleteOnClose {View on GitHub (pinned to 4ed7a308f6)
Solutions
- Ensure the same VFS instance performs open and delete; avoid recreating the VFS between operations.
- Treat the file as already gone if DeleteOnClose removed it; check the registry presence before deleting programmatically.
- Remove the underlying local file directly (its hashed temp path) if you only need the bytes gone.
- If this recurs under normal SQLite operation, report it — SQLite should only delete files it opened.
Example fix
// before db.Close() vfs.Delete(name, false) // already untracked by DeleteOnClose // after db.Close() // DeleteOnClose already removed the temp file; skip manual delete
Defensive patterns
Strategy: try-catch
Validate before calling
// check registry membership before delete, if the API exposes it
if !vfs.TracksTempFile(name) { return nil } Try / catch
if errors.Is(err, errTempFileNotFound) || strings.Contains(err.Error(), "cannot delete vfs file") {
// treat as already-deleted; optionally os.Remove local temp path
} Prevention
- Never double-delete temp journal names.
- Use DeleteOnClose consistently instead of manual deletes.
- Keep open/delete on the same VFS instance.
- After restarts, don't reuse stale file references.
When it happens
Trigger: xDelete on a temp-style name that was never opened via this VFS, was already deleted (registry entry removed, e.g. by DeleteOnClose), or after a restart when the registry is empty; also from deleteTempFile's cleanup path when a lookup misses.
Common situations: Double-delete of the same temp journal; connection closed with DeleteOnClose removing the mapping before SQLite issues xDelete; multiple VFS instances where the file was opened on a different instance.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- cannot delete vfs file
- create temp dir for hydration: %w
- invalid temp file name: %q
- hash temp name: %w
- clear write buffer: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/75be7c2b1c316318.
Report an issue: GitHub.