golang-migrate/migrate · error
source driver: invalid URL scheme
Error message
source driver: invalid URL scheme
What it means
Raised by source.Open in source/driver.go when the parsed migration source URL has an empty URL scheme. The driver registry is keyed by scheme, so without a scheme the library cannot select a source driver and refuses to proceed.
Source
Thrown at source/driver.go:83
ReadUp(version uint) (r io.ReadCloser, identifier string, err error)
// ReadDown returns the DOWN migration body and an identifier that helps
// finding this migration in the source for a given version.
// If there is no down migration available for this version,
// it must return os.ErrNotExist.
// Do not start reading, just return the ReadCloser!
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")View on GitHub (pinned to 01a9643f14)
Solutions
- Prefix the URL with its scheme, e.g. 'github://', 'file://', 's3://'
- Verify the env var or config value supplying the URL is not empty/truncated
- Log or print the URL right before source.Open to confirm what is actually passed
Example fix
// before
source.Open("github.com/user/repo/migrations")
// after
source.Open("github://user:token@github.com/user/repo/migrations") Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(sourceURL)
if err != nil {
return fmt.Errorf("bad source url: %w", err)
}
if u.Scheme == "" {
return fmt.Errorf("source url %q missing scheme (want e.g. github://, file://)", sourceURL)
} Type guard
func hasScheme(raw string) bool {
u, err := url.Parse(raw)
return err == nil && u.Scheme != ""
} Try / catch
d, err := source.Open(sourceURL)
if err != nil {
if strings.Contains(err.Error(), "invalid URL scheme") {
return fmt.Errorf("check source URL %q: %w", sourceURL, err)
}
return err
} Prevention
- Always store full driver-qualified URLs including scheme://
- Validate URLs at config load time, before calling Open
- Keep source URLs in dedicated, clearly named config keys
When it happens
Trigger: Calling source.Open (or migrate.New with a source URL string) with a URL that has no 'scheme://' prefix, e.g. Open('github.com/user/repo') instead of Open('github://user:token@github.com/user/repo'), or a URL built by string concatenation that lost its prefix.
Common situations: Hand-written config files where the scheme was accidentally dropped, environment variables expanded to empty (missing MIGRATE_SOURCE env prefix), or URLs copied from docs with the scheme omitted.
Related errors
- URL cannot be empty
- source driver: unknown driver '%s' (forgotten import?)
- invalid repo
- no config
- no keyspace provided
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/63fff159bad79814.
Report an issue: GitHub.