{"record":{"id":"d46e8df7b79ef65e","repo":"golang-migrate/migrate","slug":"source-driver-unknown-driver-s-forgotten-impo","errorCode":null,"errorMessage":"source driver: unknown driver '%s' (forgotten import?)","messagePattern":"source driver: unknown driver '(.+?)' \\(forgotten import\\?\\)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"source/driver.go","lineNumber":90,"sourceCode":"\tReadDown(version uint) (r io.ReadCloser, identifier string, err error)\n}\n\n// Open returns a new driver instance.\nfunc Open(url string) (Driver, error) {\n\tu, err := nurl.Parse(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif u.Scheme == \"\" {\n\t\treturn nil, fmt.Errorf(\"source driver: invalid URL scheme\")\n\t}\n\n\tdriversMu.RLock()\n\td, ok := drivers[u.Scheme]\n\tdriversMu.RUnlock()\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"source driver: unknown driver '%s' (forgotten import?)\", u.Scheme)\n\t}\n\n\treturn d.Open(url)\n}\n\n// Register globally registers a driver.\nfunc Register(name string, driver Driver) {\n\tdriversMu.Lock()\n\tdefer driversMu.Unlock()\n\tif driver == nil {\n\t\tpanic(\"Register driver is nil\")\n\t}\n\tif _, dup := drivers[name]; dup {\n\t\tpanic(\"Register called twice for driver \" + name)\n\t}\n\tdrivers[name] = driver\n}\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/golang-migrate/migrate/blob/01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a/source/driver.go#L72-L108","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add a blank import for the driver: _ \"github.com/golang-migrate/migrate/v4/source/github\" (matching the scheme)","Check the scheme spelling in the URL against the registered driver name","If using the CLI, ensure it was built with the required driver (or use a build that includes it)"],"exampleFix":"// before\nimport (\n    \"github.com/golang-migrate/migrate/v4\"\n)\n// after\nimport (\n    \"github.com/golang-migrate/migrate/v4\"\n    _ \"github.com/golang-migrate/migrate/v4/source/github\"\n)","handlingStrategy":"validation","validationCode":"import (\n    _ \"github.com/golang-migrate/migrate/v4/source/github\"\n    _ \"github.com/golang-migrate/migrate/v4/source/gitlab\"\n)\n\n// then, before Open:\nknown := []string{\"github\", \"gitlab\", \"file\", \"s3\"}\nscheme := parsed.Scheme\nif !slices.Contains(known, scheme) {\n    return fmt.Errorf(\"unsupported source scheme %q\", scheme)\n}","typeGuard":"func driverRegistered(scheme string) bool {\n    _, err := source.Open(scheme + \"://probe\")\n    return !strings.Contains(err.Error(), \"unknown driver\")\n}","tryCatchPattern":"d, err := source.Open(srcURL)\nif err != nil {\n    if strings.Contains(err.Error(), \"unknown driver\") {\n        return fmt.Errorf(\"forgot blank import for source driver in %q? %w\", srcURL, err)\n    }\n    return err\n}","preventionTips":["Blank-import every source/database driver you use in each binary","Keep the import list in a single drivers.go file per service","Match URL scheme exactly to the name passed to source.Register"],"tags":["source-driver","imports","configuration"],"backgroundTag":"unknown-driver-forgotten-import","analyzedSha":"01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a","analyzedAt":"2026-09-02T19:38:29.671Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}