golang-migrate/migrate · error

failed to init driver with path %s: %w

Error message

failed to init driver with path %s: %w

What it means

New wraps any error returned by the iofs driver's Init (the underlying iofs passthrough driver initialization) with context about the path: 'failed to init driver with path %s: %w'. It signals that the given io/fs filesystem plus relative path could not be initialized — most commonly because the path does not exist or is not a directory within the provided fs.FS.

Source

Thrown at source/iofs/iofs.go:24

	"errors"
	"fmt"
	"io"
	"io/fs"
	"path"
	"strconv"

	"github.com/golang-migrate/migrate/v4/source"
)

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

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Verify the path exists inside the fs.FS: fs.Stat(fsys, path) and confirm it is a directory before calling New
  2. With embed.FS, check the //go:embed pattern — embed 'migrations/*' requires passing 'migrations' as path, while embedding into a migrations package may need "."
  3. Print available entries with fs.ReadDir(fsys, ".") to see the actual structure and correct the path
  4. Read the wrapped error (%v on the result) for the root cause, e.g. 'file does not exist'

Example fix

// before
//go:embed migrations
var fsys embed.FS
d, err := iofs.New(fsys, "migrations") // ok if pattern is 'migrations'
// if pattern is 'migrations/*.sql' inside package migrations:
d, err := iofs.New(fsys, ".")
Defensive patterns

Strategy: validation

Validate before calling

func mustDir(fsys fs.FS, path string) error {
    fi, err := fs.Stat(fsys, path)
    if err != nil {
        return fmt.Errorf("path %q in fs: %w", path, err)
    }
    if !fi.IsDir() {
        return fmt.Errorf("%q is not a directory", path)
    }
    entries, _ := fs.ReadDir(fsys, path)
    if len(entries) == 0 {
        return fmt.Errorf("%q contains no migration files", path)
    }
    return nil
}

Try / catch

d, err := iofs.New(fsys, "migrations")
if err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) {
        return fmt.Errorf("bad migrations path %q: %w", perr.Path, err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling iofs.New(fsys, path) where fs.Stat(fsys, path) fails or the entry is not a directory — e.g. embedding migrations via embed.FS with an incorrect path prefix (embed paths do not include the 'migrations' directory unless embedded as such).

Common situations: embed.FS path confusion (//go:embed migrations yields entries prefixed 'migrations/' or not, depending on embed pattern); typo'd path; passing a file instead of a directory; using os.DirFS with a wrong root.

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


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