{"record":{"id":"5bd13091d12f74fb","repo":"golang/go","slug":"config-importer-import-s-returned-nil-but-no-err","errorCode":null,"errorMessage":"Config.Importer.Import(%s) returned nil but no error","messagePattern":"Config\\.Importer\\.Import\\((.+?)\\) returned nil but no error","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/compile/internal/types2/resolver.go","lineNumber":158,"sourceCode":"\t\t\tcheck.error(pos, BadImportPath, \"cannot use FakeImportC and go115UsesCgo together\")\n\t\t}\n\t\timp = NewPackage(\"C\", \"C\")\n\t\timp.fake = true // package scope is not populated\n\t\timp.cgo = check.conf.go115UsesCgo\n\t} else {\n\t\t// ordinary import\n\t\tvar err error\n\t\tif importer := check.conf.Importer; importer == nil {\n\t\t\terr = fmt.Errorf(\"Config.Importer not installed\")\n\t\t} else if importerFrom, ok := importer.(ImporterFrom); ok {\n\t\t\timp, err = importerFrom.ImportFrom(path, dir, 0)\n\t\t\tif imp == nil && err == nil {\n\t\t\t\terr = fmt.Errorf(\"Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error\", path, dir)\n\t\t\t}\n\t\t} else {\n\t\t\timp, err = importer.Import(path)\n\t\t\tif imp == nil && err == nil {\n\t\t\t\terr = fmt.Errorf(\"Config.Importer.Import(%s) returned nil but no error\", path)\n\t\t\t}\n\t\t}\n\t\t// make sure we have a valid package name\n\t\t// (errors here can only happen through manipulation of packages after creation)\n\t\tif err == nil && imp != nil && (imp.name == \"_\" || imp.name == \"\") {\n\t\t\terr = fmt.Errorf(\"invalid package name: %q\", imp.name)\n\t\t\timp = nil // create fake package below\n\t\t}\n\t\tif err != nil {\n\t\t\tcheck.errorf(pos, BrokenImport, \"could not import %s (%s)\", path, err)\n\t\t\tif imp == nil {\n\t\t\t\t// create a new fake package\n\t\t\t\t// come up with a sensible package name (heuristic)\n\t\t\t\tname := strings.TrimSuffix(path, \"/\")\n\t\t\t\tif i := strings.LastIndex(name, \"/\"); i >= 0 {\n\t\t\t\t\tname = name[i+1:]\n\t\t\t\t}\n\t\t\t\timp = NewPackage(path, name)","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/compile/internal/types2/resolver.go#L140-L176","documentation":"Thrown by the types2 type checker's resolver when an installed Config.Importer's Import(path) method returns a nil *Package together with a nil error. The Go importer contract requires that a nil package always be accompanied by a non-nil error; returning both nil is a programmer error in the importer implementation. This guard converts that silent contract violation into an explicit BrokenImport so type checking can proceed with a synthetic fake package instead of panicking.","triggerScenarios":"Produced when check.conf.Importer is non-nil, does NOT satisfy ImporterFrom, and calling importer.Import(path) on some import path yields (nil, nil). Only reachable through go/types or cmd/compile/internal/types2 Config.Check / Importer usage with a custom or third-party importer.","commonSituations":"A hand-written types.Importer whose Import returns (nil, nil) on a missing/unresolved path instead of returning an error. Bug in a vendored importer shim. Mock importer used in tests that forgets to set an error.","solutions":["Fix the importer so Import never returns (nil, nil) — return a non-nil error whenever the package is nil","If using a custom importer, verify every error path actually returns an error before returning a nil package","Switch to an importer that implements ImporterFrom (ImportFrom) so the ImportFrom branch is taken instead","Reproduce with a logging wrapper around the importer to find which import path triggers the nil/nil return"],"exampleFix":"// before\ndef (i *myImporter) Import(path string) (*types.Package, error) {\n    pkg := i.cache[path]\n    if pkg == nil {\n        return nil, nil // bug\n    }\n    return pkg, nil\n}\n// after\ndef (i *myImporter) Import(path string) (*types.Package, error) {\n    pkg := i.cache[path]\n    if pkg == nil {\n        return nil, fmt.Errorf(\"package %q not found\", path)\n    }\n    return pkg, nil\n}","handlingStrategy":"validation","validationCode":"// Wrap any custom importer to enforce the (pkg, err) contract:\ntype safeImporter struct{ inner types.Importer }\nfunc (s safeImporter) Import(path string) (*types.Package, error) {\n    pkg, err := s.inner.Import(path)\n    if pkg == nil && err == nil {\n        return nil, fmt.Errorf(\"importer returned nil package without error for %q\", path)\n    }\n    return pkg, err\n}\n// Use: conf.Importer = safeImporter{inner: myImporter}","typeGuard":"// go has no sum type here; guard by interface satisfaction:\nif _, ok := conf.Importer.(types2.ImporterFrom); !ok {\n    // Import() path will be used; ensure it never returns (nil,nil)\n}","tryCatchPattern":"// In Go, check both returns explicitly:\npkg, err := importer.Import(path)\nif err != nil { return err }\nif pkg == nil { return fmt.Errorf(\"nil package for %q\", path) }","preventionTips":["Never let a custom Import/ImportFrom return (nil, nil)","Wrap third-party importers with a contract-enforcing decorator","Unit-test the importer against unresolved paths and assert an error is returned"],"tags":["go-toolchain","type-checker","importer","api-contract"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}