benbjohnson/litestream · error
vfs file not found: id=%d
Error message
vfs file not found: id=%d
What it means
RegisterVFSConnection maps a SQLite connection pointer (dbPtr) to a VFS file ID. Before storing the mapping it checks that the file ID exists via lookupVFSFile; if not, it refuses to register. This guards against registering connections for files that were already closed or never opened through the VFS.
Source
Thrown at vfs.go:2859
return infos, nil
}
if !errors.Is(err, ErrTxNotAvailable) {
return nil, fmt.Errorf("cannot calc restore plan: %w", err)
}
f.logger.Debug("no backup files available yet, waiting", "interval", f.PollInterval)
select {
case <-time.After(f.PollInterval):
case <-f.ctx.Done():
return nil, fmt.Errorf("no backup files available: %w", f.ctx.Err())
}
}
}
// RegisterVFSConnection maps a SQLite connection handle to its VFS file ID.
func RegisterVFSConnection(dbPtr uintptr, fileID uint64) error {
if _, ok := lookupVFSFile(fileID); !ok {
return fmt.Errorf("vfs file not found: id=%d", fileID)
}
vfsConnectionMap.Store(dbPtr, fileID)
return nil
}
// UnregisterVFSConnection removes a connection mapping.
func UnregisterVFSConnection(dbPtr uintptr) {
vfsConnectionMap.Delete(dbPtr)
}
// SetVFSConnectionTime rebuilds the VFS index for a connection at a timestamp.
func SetVFSConnectionTime(dbPtr uintptr, timestamp string) error {
file, err := vfsFileForConnection(dbPtr)
if err != nil {
return err
}
t, err := parseTimeValue(timestamp)View on GitHub (pinned to 4ed7a308f6)
Solutions
- Open the database through the VFS first and use the file ID returned from that open
- Check for double-close races: ensure the file is not unregistered before connection registration
- Log/verify the fileID matches the one returned by your latest VFS open call
Example fix
// before: stale id after reopen fileID := cachedID litestreamvfs.RegisterVFSConnection(dbPtr, fileID) // vfs file not found // after: use id from the current open file, fileID := litestreamvfs.Open(dbPath) _ = litestreamvfs.RegisterVFSConnection(dbPtr, fileID)
Defensive patterns
Strategy: validation
Validate before calling
func ensureFileRegistered(fileID uint64) error {
if _, ok := lookupVFSFile(fileID); !ok {
return fmt.Errorf("cannot register connection: vfs file %d not open", fileID)
}
return nil
} Type guard
func hasVFSFile(fileID uint64) bool { _, ok := lookupVFSFile(fileID); return ok } Try / catch
if err := litestreamvfs.RegisterVFSConnection(dbPtr, fileID); err != nil {
if strings.Contains(err.Error(), "vfs file not found") {
return reopenAndRegister(ctx)
}
return err
} Prevention
- Always register with the fileID returned by the current open
- Never cache file IDs across reopen cycles
- Fix any prior registration errors immediately instead of ignoring them
When it happens
Trigger: Calling litestream_vfs_register_connection (or the Go API) with a fileID that was never created by the VFS open, or whose VFSFile was already unregistered/closed.
Common situations: Application-level cache of stale file IDs after reopening the database; concurrent close of the VFS file while another goroutine registers its connection; passing the wrong ID after multiple database opens.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- connection not registered
- remote has newer transactions than expected
- close db: %w
- create per-connection replica client: %w
- no replica client configured: set LITESTREAM_REPLICA_URL, us
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/29d2f5f330886c9b.
Report an issue: GitHub.