golang-migrate/migrate · error

source driver: unknown driver '%s' (forgotten import?)

Error message

source driver: unknown driver '%s' (forgotten import?)

What it means

Raised by source.Open when the URL scheme is valid but no driver is registered under that scheme. Drivers self-register via init() when their package is imported, so this almost always means the driver package was never imported (blank import) or the scheme is misspelled.

Source

Thrown at source/driver.go:90

	ReadDown(version uint) (r io.ReadCloser, identifier string, err error)
}

// Open returns a new driver instance.
func Open(url string) (Driver, error) {
	u, err := nurl.Parse(url)
	if err != nil {
		return nil, err
	}

	if u.Scheme == "" {
		return nil, fmt.Errorf("source driver: invalid URL scheme")
	}

	driversMu.RLock()
	d, ok := drivers[u.Scheme]
	driversMu.RUnlock()
	if !ok {
		return nil, fmt.Errorf("source driver: unknown driver '%s' (forgotten import?)", u.Scheme)
	}

	return d.Open(url)
}

// Register globally registers a driver.
func Register(name string, driver Driver) {
	driversMu.Lock()
	defer driversMu.Unlock()
	if driver == nil {
		panic("Register driver is nil")
	}
	if _, dup := drivers[name]; dup {
		panic("Register called twice for driver " + name)
	}
	drivers[name] = driver
}

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Add a blank import for the driver: _ "github.com/golang-migrate/migrate/v4/source/github" (matching the scheme)
  2. Check the scheme spelling in the URL against the registered driver name
  3. If using the CLI, ensure it was built with the required driver (or use a build that includes it)

Example fix

// before
import (
    "github.com/golang-migrate/migrate/v4"
)
// after
import (
    "github.com/golang-migrate/migrate/v4"
    _ "github.com/golang-migrate/migrate/v4/source/github"
)
Defensive patterns

Strategy: validation

Validate before calling

import (
    _ "github.com/golang-migrate/migrate/v4/source/github"
    _ "github.com/golang-migrate/migrate/v4/source/gitlab"
)

// then, before Open:
known := []string{"github", "gitlab", "file", "s3"}
scheme := parsed.Scheme
if !slices.Contains(known, scheme) {
    return fmt.Errorf("unsupported source scheme %q", scheme)
}

Type guard

func driverRegistered(scheme string) bool {
    _, err := source.Open(scheme + "://probe")
    return !strings.Contains(err.Error(), "unknown driver")
}

Try / catch

d, err := source.Open(srcURL)
if err != nil {
    if strings.Contains(err.Error(), "unknown driver") {
        return fmt.Errorf("forgot blank import for source driver in %q? %w", srcURL, err)
    }
    return err
}

Prevention

When it happens

Trigger: source.Open('githubs://...') (typo), or using a driver like 'github://', 's3://' or 'gitlab://' without importing _ 'github.com/golang-migrate/migrate/v4/source/github' (etc.) in the binary.

Common situations: Building a custom binary that uses migrate programmatically and forgetting the blank import; renaming schemes between versions; CLI users hitting a build of the tool that excludes that driver.

Related errors


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