golang-migrate/migrate · error
failed to init driver with relative path %q: %w
Error message
failed to init driver with relative path %q: %w
What it means
golang-migrate's pkger source driver wraps a go-pkger embedded filesystem. Open(url) parses the URL and calls Init on the driver with the URL's path; if Init fails (e.g. the path does not exist inside the embedded pkger filesystem), the underlying error is wrapped as "failed to init driver with relative path %q: %w".
Source
Thrown at source/pkger/pkger.go:45
// migrations must be added to the global pkger.Pkger instance by calling
// pkger.Apply. Refer to Pkger documentation for more information.
func (p *Pkger) Open(url string) (source.Driver, error) {
u, err := stdurl.Parse(url)
if err != nil {
return nil, err
}
// wrap pkger to implement http.FileSystem.
fs := fsFunc(func(name string) (http.File, error) {
f, err := pkger.Open(name)
if err != nil {
return nil, err
}
return f.(http.File), nil
})
if err := p.Init(fs, u.Path); err != nil {
return nil, fmt.Errorf("failed to init driver with relative path %q: %w", u.Path, err)
}
return p, nil
}
// WithInstance returns a source.Driver that is backed by an instance of
// pkging.Pkger. The relative location of migrations is indicated by path. The
// path must exist on the pkging.Pkger instance for the driver to initialize
// successfully.
func WithInstance(instance pkging.Pkger, path string) (source.Driver, error) {
if instance == nil {
return nil, fmt.Errorf("expected instance of pkging.Pkger")
}
// wrap pkger to implement http.FileSystem.
fs := fsFunc(func(name string) (http.File, error) {
f, err := instance.Open(name)
if err != nil {View on GitHub (pinned to 01a9643f14)
Solutions
- Regenerate the pkger bundle (pkger -include /migrations) so the path exists in the embedded filesystem, then rebuild.
- Verify the path component of the pkger URL exactly matches an existing directory in the pkger instance (case-sensitive).
- Inspect the wrapped error (errors.Unwrap / %w chain) from p.Init to see the root cause (e.g. file does not exist).
- Ensure migrations were embedded before running tests in CI; pkger assets are only present after generation.
Example fix
// before (URL points to missing dir)
m, err := migrate.New("pkger:///migrats", "postgres://...")
// after
go run github.com/markbates/pkger/cmd/pkger -include /migrations
m, err := migrate.New("pkger:///migrations", "postgres://...") Defensive patterns
Strategy: validation
Validate before calling
// before building the URL, confirm the embedded path exists
f, err := pkger.Open("/migrations")
if err != nil {
return fmt.Errorf("pkger path /migrations not embedded: %w", err)
}
f.Close()
m, err := migrate.New("pkger:///migrations", dsn) Try / catch
if err != nil {
if strings.Contains(err.Error(), "failed to init driver with relative path") {
// inspect errors.Unwrap(err) for the root cause; fix embed path and rebuild
}
return err
} Prevention
- Run the pkger generator in your build pipeline before compiling/running migrations.
- Add a startup check that pkger.Open(migrationsDir) succeeds.
- Keep the pkger URL path and the embedded directory in one shared constant.
When it happens
Trigger: Calling migrate.New with a pkger:// URL whose embedded path does not exist inside the go-pkger package, e.g. source/pkger!migrations not included at build time, or a typo'd subdirectory in the URL path.
Common situations: Using pkger to embed migrations but forgetting to run the pkger tool before building, migrations living in a directory different from the URL path, or renaming the migrations folder without updating the URL.
Related errors
- expected instance of pkging.Pkger
- Register driver is nil
- Register called twice for driver
- Register driver is nil
- Register called twice for driver
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/54b195439f28c166.
Report an issue: GitHub.