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 making

View on GitHub (pinned to b6b368adc5)

Solutions

  1. For a local replacement, verify the path exists and contains a go.mod: 'ls <replacePath>/go.mod'.
  2. Fix GOPROXY/GONOSUMCHECK/network so the proxy can serve remote go.mod files.
  3. Check file permissions on the module cache and the replacement directory.
  4. 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

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


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