golang-migrate/migrate · error

open() cannot be called on the iofs passthrough driver

Error message

open() cannot be called on the iofs passthrough driver

What it means

The iofs package wraps an io/fs.FS as a migration source. Its driver's Open method is deliberately unimplemented — instances are created by WithInstance(fsys), not through the URL registry — so any call to Open returns this error. It exists only to complete the source.Driver interface.

Solutions

  1. Use iofs.WithInstance(fsys) (e.g. with an embed.FS) and pass the result via migrate.NewWithSourceInstance("iofs", d, databaseURL).
  2. When embedding PartialDriver in a custom driver, override Open with a real constructor that returns your driver for valid URLs.
  3. Do not register the passthrough driver in the URL scheme registry.

Example fix

// before
m, err := migrate.New("iofs://embedded", dsn)
// after
d, err := iofs.WithInstance(migrationsFS)
m, err := migrate.NewWithSourceInstance("iofs", d, dsn)
Defensive patterns

Strategy: validation

Validate before calling

d, err := iofs.WithInstance(embeddedFS)
if err != nil { return err }
m, err := migrate.NewWithSourceInstance("iofs", d, databaseURL)

Try / catch

if err != nil && strings.Contains(err.Error(), "iofs passthrough") {
    return fmt.Errorf("iofs drivers must be created with iofs.WithInstance, not Open")
}

Prevention

When it happens

Trigger: Calling Open on the driver returned by iofs.WithInstance; registering the iofs driver under a URL scheme and then invoking source.Open("iofs://...").

Common situations: Trying to use embed.FS-based migrations through the URL-based migrate.New API instead of migrate.NewWithSourceInstance; wrapping the passthrough driver in another driver and delegating Open to it.

Related errors


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

Appendix: source

Thrown at source/iofs/iofs.go:32

)

type driver struct {
	PartialDriver
}

// New returns a new Driver from io/fs#FS and a relative path.
func New(fsys fs.FS, path string) (source.Driver, error) {
	var i driver
	if err := i.Init(fsys, path); err != nil {
		return nil, fmt.Errorf("failed to init driver with path %s: %w", path, err)
	}
	return &i, nil
}

// Open is part of source.Driver interface implementation.
// Open cannot be called on the iofs passthrough driver.
func (d *driver) Open(url string) (source.Driver, error) {
	return nil, errors.New("open() cannot be called on the iofs passthrough driver")
}

// PartialDriver is a helper service for creating new source drivers working with
// io/fs.FS instances. It implements all source.Driver interface methods
// except for Open(). New driver could embed this struct and add missing Open()
// method.
//
// To prepare PartialDriver for use Init() function.
type PartialDriver struct {
	migrations *source.Migrations
	fsys       fs.FS
	path       string
}

// Init prepares not initialized IoFS instance to read migrations from a
// io/fs#FS instance and a relative path.
func (d *PartialDriver) Init(fsys fs.FS, path string) error {
	entries, err := fs.ReadDir(fsys, path)

View on GitHub (pinned to 01a9643f14)