{"record":{"id":"5f1b25a960094e65","repo":"golang/go","slug":"config-importer-importfrom-s-s-0-returned-nil","errorCode":null,"errorMessage":"Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error","messagePattern":"Config\\.Importer\\.ImportFrom\\((.+?), (.+?), 0\\) returned nil but no error","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/compile/internal/types2/resolver.go","lineNumber":153,"sourceCode":"\t}\n\n\t// no package yet => import it\n\tif path == \"C\" && (check.conf.FakeImportC || check.conf.go115UsesCgo) {\n\t\tif check.conf.FakeImportC && check.conf.go115UsesCgo {\n\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)","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/compile/internal/types2/resolver.go#L135-L171","documentation":"When the type checker's Config.Importer implements the ImporterFrom interface, it calls ImportFrom(path, dir, 0). If the importer returns (nil, nil) — a nil package with no error — this violates the importer contract. A nil package must always be accompanied by an error explaining why the import failed. This error is synthesized by the type checker to flag the contract violation.","triggerScenarios":"A custom types.Importer implementation whose ImportFrom method returns (nil, nil) for a not-found or error case instead of returning a proper error. Incomplete or buggy mock importer implementations in tests. Importers that swallow errors internally and return nil.","commonSituations":"Custom importer implementations in static analysis tools that have bugs in error handling. Mock importers in unit tests that don't properly simulate the error contract. Importers that check a cache and return nil on miss without falling through to actual resolution.","solutions":["Fix the custom importer to always return a non-nil error when the package is nil","Use importer.Default() or go/packages instead of a custom implementation","Add a defensive guard in the importer: if pkg == nil && err == nil { err = fmt.Errorf(\"import %q failed\", path) }","Write unit tests for the custom importer that verify it never returns (nil, nil)"],"exampleFix":"// before — buggy custom importer\nfunc (m *MyImporter) ImportFrom(path, dir string, mode types.ImportMode) (*types.Package, error) {\n    pkg := m.cache[path]\n    if pkg == nil {\n        return nil, nil // BUG: contract violation\n    }\n    return pkg, nil\n}\n\n// after — fixed\nfunc (m *MyImporter) ImportFrom(path, dir string, mode types.ImportMode) (*types.Package, error) {\n    pkg := m.cache[path]\n    if pkg == nil {\n        return nil, fmt.Errorf(\"package %q not found in cache\", path)\n    }\n    return pkg, nil\n}","handlingStrategy":"validation","validationCode":"// Wrap a custom importer to enforce the (nil package => non-nil error) contract\ntype safeImporter struct {\n    inner types.Importer\n}\n\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 for %q without error\", path)\n    }\n    return pkg, err\n}\n\nfunc (s *safeImporter) ImportFrom(path, dir string, mode types.ImportMode) (*types.Package, error) {\n    if imp, ok := s.inner.(types.ImporterFrom); ok {\n        pkg, err := imp.ImportFrom(path, dir, mode)\n        if pkg == nil && err == nil {\n            return nil, fmt.Errorf(\"ImportFrom returned nil package for %q without error\", path)\n        }\n        return pkg, err\n    }\n    return s.Import(path)\n}\n\n// Usage: conf.Importer = &safeImporter{inner: myCustomImporter}","typeGuard":"// Verify a custom importer satisfies the contract in tests\nfunc assertImporterContract(imp types.Importer) error {\n    // Test with a path that should not resolve\n    _, err := imp.Import(\"github.com/nonexistent/pkg/that/does/not/exist\")\n    // If err is nil and we get here, check if we got a nil package\n    // (the real test is that Import never returns (nil, nil))\n    if err == nil {\n        // If no error for a nonexistent package, the importer is too permissive\n        // but that's not a contract violation per se\n    }\n    return nil\n}","tryCatchPattern":null,"preventionTips":["Always return a non-nil error from custom Importer implementations when the package is nil","Wrap custom importers with a safeImporter guard that enforces the contract","Write unit tests that call Import with non-existent paths and verify an error is returned","Prefer using importer.Default() or go/packages over custom importer implementations"],"tags":["go-types","go-imports","api-contract","custom-importer"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}