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

  1. Open the database through the VFS first and use the file ID returned from that open
  2. Check for double-close races: ensure the file is not unregistered before connection registration
  3. 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

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


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/29d2f5f330886c9b. Report an issue: GitHub.