golang/go · error
error reading module index: %v
Error message
error reading module index: %v
What it means
Recovery error from unprotect() after a panic during large-scale module-index access. It fires only when the recovered value satisfies the addrer interface (a SetPanicOnFault memory-access fault) OR equals the errCorrupt sentinel — i.e. the on-disk index is unreadable or structurally invalid. The wrapped %v is the panic value. If errp is nil the message is passed to base.Fatalf; in tests it is re-panicked.
Source
Thrown at src/cmd/go/internal/modindex/read.go:283
// defer unprotect(protect, &err)
//
// end looks for panics due to errCorrupt or bad mmap accesses.
// When it finds them, it adds explanatory text, consumes the panic, and sets *errp instead.
// If errp is nil, end adds the explanatory text but then calls base.Fatalf.
func unprotect(old bool, errp *error) {
// SetPanicOnFault's errors _may_ satisfy this interface. Even though it's not guaranteed
// that all its errors satisfy this interface, we'll only check for these errors so that
// we don't suppress panics that could have been produced from other sources.
type addrer interface {
Addr() uintptr
}
debug.SetPanicOnFault(old)
if e := recover(); e != nil {
if _, ok := e.(addrer); ok || e == errCorrupt {
// This panic was almost certainly caused by SetPanicOnFault or our panic(errCorrupt).
err := fmt.Errorf("error reading module index: %v", e)
if errp != nil {
*errp = err
return
}
if isTest {
panic(err)
}
base.Fatalf("%v", err)
}
// The panic was likely not caused by SetPanicOnFault.
panic(e)
}
}
// fromBytes returns a *Module given the encoded representation.
func fromBytes(moddir string, data []byte) (m *Module, err error) {
if !enabled {
panic("use of index")View on GitHub (pinned to b6b368adc5)
Solutions
- Clear the module cache and let Go rebuild it: `go clean -modcache`.
- Re-run the failing command — `go mod download` regenerates the index.
- If on a network filesystem, move GOMODCACHE to a local disk.
- Verify disk health / free space; check dmesg for filesystem errors.
Defensive patterns
Strategy: fallback
Validate before calling
// Defensive wrapper: if the index read fails, fall back to the live filesystem.
func importWithFallback(modroot, dir string) (*build.Package, error) {
if pkg, err := modindex.OpenPackage(modroot, dir); err == nil {
return pkg, nil
}
// index unreadable — recompute directly
return build.ImportDir(filepath.Join(modroot, dir), 0)
} Try / catch
// Treat index-read errors as recoverable: clear cache once and retry.
pkg, err := modindex.OpenPackage(modroot, dir)
if err != nil && strings.Contains(err.Error(), "error reading module index") {
_ = os.RemoveAll(filepath.Join(os.Getenv("GOMODCACHE"), "cache/download"))
pkg, err = modindex.OpenPackage(modroot, dir)
}
return pkg, err Prevention
- Do not share GOMODCACHE across Go toolchain major versions.
- Add `go clean -modcache` to CI on cache-provider rotation.
- Monitor disk health where the module cache lives.
When it happens
Trigger: Any index read wrapped by protect()/unprotect() (e.g. fromBytes) when the mmap'd index file is truncated, partially overwritten, or accessed past its end. SetPanicOnFault turns the bad memory access into a recoverable panic that unprotect converts into this error.
Common situations: GOMODCACHE corrupted by a killed `go mod download`, concurrent writers racing the index, disk full mid-write, third-party tools mutating files under the cache, or an OS-level mmap fault on a network filesystem.
Related errors
- corrupt single-package index
- not a directory
- not completely extracted
- corrupt index
- short write writing body to GOCACHEPROG for action %x, outpu
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/094779e9a021630c.
Report an issue: GitHub.