golang/go · error
reading %s: %v
Error message
reading %s: %v
What it means
Returned from rawGoModData when reading the go.mod bytes for a module fails at the I/O layer. For versioned modules this wraps an error from the module proxy/fetcher GoMod() call; for a filesystem replacement (m.Version=="") it wraps a lockedfile.Read / os.ReadFile failure on the local go.mod path. Wrapped in module.VersionError to name the module.
Source
Thrown at src/cmd/go/internal/modload/modfile.go:805
if !filepath.IsAbs(dir) {
if ld.inWorkspaceMode() && ld.MainModules.Contains(m.Path) {
dir = ld.MainModules.ModRoot(m)
} else {
// m is a replacement module with only a file path.
dir = filepath.Join(replaceRelativeTo(ld), dir)
}
}
name = filepath.Join(dir, "go.mod")
if fsys.Replaced(name) {
// Don't lock go.mod if it's part of the overlay.
// On Plan 9, locking requires chmod, and we don't want to modify any file
// in the overlay. See #44700.
data, err = os.ReadFile(fsys.Actual(name))
} else {
data, err = lockedfile.Read(name)
}
if err != nil {
return "", nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(name), err))
}
} else {
if !gover.ModIsValid(m.Path, m.Version) {
// Disallow the broader queries supported by fetch.Lookup.
base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version)
}
name = "go.mod"
data, err = ld.Fetcher().GoMod(context.TODO(), m.Path, m.Version)
}
return name, data, err
}
// queryLatestVersionIgnoringRetractions looks up the latest version of the
// module with the given path without considering retracted or excluded
// versions.
//
// If all versions of the module are replaced,
// queryLatestVersionIgnoringRetractions returns the replacement without makingView on GitHub (pinned to b6b368adc5)
Solutions
- For a local replacement, verify the path exists and contains a go.mod: 'ls <replacePath>/go.mod'.
- Fix GOPROXY/GONOSUMCHECK/network so the proxy can serve remote go.mod files.
- Check file permissions on the module cache and the replacement directory.
- Use an absolute path in the replace directive to avoid working-directory ambiguity.
Example fix
// before replace example.com/pkg => ./pkg // ./pkg/go.mod missing // error: reading ./pkg/go.mod: no such file or directory // after replace example.com/pkg => ./pkghas // directory that contains go.mod
Defensive patterns
Strategy: validation
Validate before calling
// For local replacements, confirm the file exists before building:
// if _, err := os.Stat(filepath.Join(replaceDir, "go.mod")); err != nil { /* fix path */ } Type guard
func replaceGoModExists(dir string) bool {
_, err := os.Stat(filepath.Join(dir, "go.mod"))
return err == nil
} Prevention
- Use absolute paths in replace directives to avoid working-directory ambiguity.
- Add a CI step that runs 'go mod download' to surface unreachable proxies/paths.
- Document replacement targets so contributors do not delete the referenced directories.
When it happens
Trigger: A replacement directive points at a local directory whose go.mod is missing or unreadable; the module proxy is unreachable or returns an error for the go.mod endpoint; permission denied on the cached file; the replacement path is relative and resolves incorrectly.
Common situations: replace directive with a wrong or non-existent local path; GOPROXY misconfigured or down; filesystem permissions block reading vendor/cache; relative replacement path evaluated from the wrong working directory.
Related errors
- reading %s: %v
- error opening file created by 'svn export': %v
- updating go.sum: %w
- read %s: %v
- loading deprecation for %s: %w
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/f739fb167c0bcc43.
Report an issue: GitHub.