golang-migrate/migrate · error

not implemented

Error message

not implemented

What it means

VFS.Open intentionally panics with "not implemented": a VFS-backed source driver cannot be constructed from a URL because the underlying virtual filesystem must be supplied as a value. The package docs say to use godoc_vfs.WithInstance instead; Open exists only to satisfy the source.Driver interface.

Source

Thrown at source/godoc_vfs/vfs.go:34

func init() {
	source.Register("godoc-vfs", &VFS{})
}

// VFS is an implementation of driver that returns migrations from a virtual
// file system.
type VFS struct {
	httpfs.PartialDriver
	fs   vfs.FileSystem
	path string
}

// Open implements the source.Driver interface for VFS.
//
// Calling this function panics, instead use the WithInstance function.
// See the package level documentation for an example.
func (b *VFS) Open(url string) (source.Driver, error) {
	panic("not implemented")
}

// WithInstance creates a new driver from a virtual file system.
// If a tree named searchPath exists in the virtual filesystem, WithInstance
// searches for migration files there.
// It defaults to "/".
func WithInstance(fs vfs.FileSystem, searchPath string) (source.Driver, error) {
	if searchPath == "" {
		searchPath = "/"
	}

	bn := &VFS{
		fs:   fs,
		path: searchPath,
	}

	if err := bn.Init(vfs_httpfs.New(fs), searchPath); err != nil {
		return nil, err

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Call godoc_vfs.WithInstance(vfsInstance, searchPath) to obtain the source.Driver instead of Open.
  2. Pass that driver to migrate.NewWithInstance(srcDrv, dbDrv) rather than using URL-based migrate.New.
  3. If you only need filesystem-based migrations, use the iofs or file source driver with a URL instead.
  4. Wrap calls in a recover() if you must call arbitrary URL schemes and treat this panic as a config error.

Example fix

// before
m, err := migrate.New("vfs:///migrations", "postgres://...") // panics
// after
src, err := godoc_vfs.WithInstance(myVfs, "/migrations")
m, err := migrate.NewWithInstance("vfs", src, "postgres", dbDrv)
Defensive patterns

Strategy: validation

Validate before calling

// never route vfs through URL-based migrate.New; use WithInstance directly
if strings.HasPrefix(url, "vfs") {
	return errors.New("vfs source requires godoc_vfs.WithInstance, not migrate.New")
}

Try / catch

func safeVfsOpen(v *godoc_vfs.VFS, url string) (src source.Driver, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("vfs.Open panicked (use WithInstance): %v", r)
		}
	}()
	return v.Open(url)
}

Prevention

When it happens

Trigger: Calling migrate.New/NewWithDatabaseConnection with a URL scheme registered to the VFS source driver, or calling vfsInstance.Open(url) directly on a godoc_vfs.VFS value.

Common situations: Treating the VFS driver like file:// or other URL-based drivers; older code using the deprecated godoc-vfs pattern (v3 and earlier) migrating to newer APIs; copy-pasted migrate.New("vfs://...", dsn) calls.

Related errors


AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02). Data as JSON: /api/errors/2a15b638de4036da. Report an issue: GitHub.