golang/go · error

Config.Importer.Import(%s) returned nil but no error

Error message

Config.Importer.Import(%s) returned nil but no error

What it means

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.

Source

Thrown at src/cmd/compile/internal/types2/resolver.go:158

			check.error(pos, BadImportPath, "cannot use FakeImportC and go115UsesCgo together")
		}
		imp = NewPackage("C", "C")
		imp.fake = true // package scope is not populated
		imp.cgo = check.conf.go115UsesCgo
	} else {
		// ordinary import
		var err error
		if importer := check.conf.Importer; importer == nil {
			err = fmt.Errorf("Config.Importer not installed")
		} else if importerFrom, ok := importer.(ImporterFrom); ok {
			imp, err = importerFrom.ImportFrom(path, dir, 0)
			if imp == nil && err == nil {
				err = fmt.Errorf("Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error", path, dir)
			}
		} else {
			imp, err = importer.Import(path)
			if imp == nil && err == nil {
				err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
			}
		}
		// make sure we have a valid package name
		// (errors here can only happen through manipulation of packages after creation)
		if err == nil && imp != nil && (imp.name == "_" || imp.name == "") {
			err = fmt.Errorf("invalid package name: %q", imp.name)
			imp = nil // create fake package below
		}
		if err != nil {
			check.errorf(pos, BrokenImport, "could not import %s (%s)", path, err)
			if imp == nil {
				// create a new fake package
				// come up with a sensible package name (heuristic)
				name := strings.TrimSuffix(path, "/")
				if i := strings.LastIndex(name, "/"); i >= 0 {
					name = name[i+1:]
				}
				imp = NewPackage(path, name)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Fix the importer so Import never returns (nil, nil) — return a non-nil error whenever the package is nil
  2. If using a custom importer, verify every error path actually returns an error before returning a nil package
  3. Switch to an importer that implements ImporterFrom (ImportFrom) so the ImportFrom branch is taken instead
  4. Reproduce with a logging wrapper around the importer to find which import path triggers the nil/nil return

Example fix

// before
def (i *myImporter) Import(path string) (*types.Package, error) {
    pkg := i.cache[path]
    if pkg == nil {
        return nil, nil // bug
    }
    return pkg, nil
}
// after
def (i *myImporter) Import(path string) (*types.Package, error) {
    pkg := i.cache[path]
    if pkg == nil {
        return nil, fmt.Errorf("package %q not found", path)
    }
    return pkg, nil
}
Defensive patterns

Strategy: validation

Validate before calling

// Wrap any custom importer to enforce the (pkg, err) contract:
type safeImporter struct{ inner types.Importer }
func (s safeImporter) Import(path string) (*types.Package, error) {
    pkg, err := s.inner.Import(path)
    if pkg == nil && err == nil {
        return nil, fmt.Errorf("importer returned nil package without error for %q", path)
    }
    return pkg, err
}
// Use: conf.Importer = safeImporter{inner: myImporter}

Type guard

// go has no sum type here; guard by interface satisfaction:
if _, ok := conf.Importer.(types2.ImporterFrom); !ok {
    // Import() path will be used; ensure it never returns (nil,nil)
}

Try / catch

// In Go, check both returns explicitly:
pkg, err := importer.Import(path)
if err != nil { return err }
if pkg == nil { return fmt.Errorf("nil package for %q", path) }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/5bd13091d12f74fb. Report an issue: GitHub.