golang-migrate/migrate · critical

Register called twice for driver

Error message

Register called twice for driver 

What it means

source.Register panics when the given source driver name already exists in the global registry. Because most source drivers register themselves in init(), importing two packages that claim the same source name (or the same package under two module versions) causes the second Register to panic.

Source

Thrown at source/driver.go:104

	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
}

// List lists the registered drivers
func List() []string {
	driversMu.RLock()
	defer driversMu.RUnlock()
	names := make([]string, 0, len(drivers))
	for n := range drivers {
		names = append(names, n)
	}
	return names
}

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Deduplicate imports / consolidate module versions so the driver registers once.
  2. Use a unique name for your custom source driver.
  3. Wrap registration in sync.Once when it cannot live in init().
  4. In tests, register distinct names per test case or construct drivers directly instead of registering.

Example fix

// before
source.Register("s3", d1)
source.Register("s3", d2) // panic
// after
source.Register("s3", d1)
source.Register("s3-custom", d2)
Defensive patterns

Strategy: validation

Validate before calling

func registerSourceOnce(name string, d source.Driver) {
	for _, n := range source.List() {
		if n == name {
			return
		}
	}
	source.Register(name, d)
}

Try / catch

defer func() {
	if r := recover(); r != nil {
		if s, ok := r.(string); ok && strings.HasPrefix(s, "Register called twice for driver") {
			log.Warnf("duplicate source driver: %s", s)
			return
		}
		panic(r)
	}
}()
source.Register(name, srcDrv)

Prevention

When it happens

Trigger: Importing two source driver packages registering the same name, one module imported at two versions in go.mod, or a custom driver registered twice (e.g. once in tests, once in init).

Common situations: Forked copies of a source driver both imported, duplicate source names in custom drivers, test suites calling Register repeatedly without isolation.

Related errors


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