golang/go · error
%s/%s and ...%s/go.mod both have ...%s module paths at revis
Error message
%s/%s and ...%s/go.mod both have ...%s module paths at revision %s
What it means
findDir (coderepo.go:868-870). Both the root go.mod (file1) and the major-subdir go.mod (file2) were read successfully and BOTH declare module paths whose major version matches pathMajor. The module system requires exactly one of them for a given major version; having both is ambiguous and rejected.
Source
Thrown at src/cmd/go/internal/modfetch/coderepo.go:869
if r.pathMajor != "" && r.codeRoot != r.modPath && !strings.HasPrefix(r.pathMajor, ".") {
// Suppose pathMajor is "/v2".
// Either go.mod should claim v2 and v2/go.mod should not exist,
// or v2/go.mod should exist and claim v2. Not both.
// Note that we don't check the full path, just the major suffix,
// because of replacement modules. This might be a fork of
// the real module, found at a different path, usable only in
// a replace directive.
dir2 := path.Join(r.codeDir, r.pathMajor[1:])
file2 = path.Join(dir2, "go.mod")
gomod2, err2 := r.code.ReadFile(ctx, rev, file2, codehost.MaxGoMod)
if err2 != nil && !os.IsNotExist(err2) {
return "", "", nil, fmt.Errorf("reading %s/%s at revision %s: %v", r.codeRoot, file2, rev, err2)
}
mpath2 := modfile.ModulePath(gomod2)
found2 := err2 == nil && isMajor(mpath2, r.pathMajor)
if found1 && found2 {
return "", "", nil, fmt.Errorf("%s/%s and ...%s/go.mod both have ...%s module paths at revision %s", r.pathPrefix, file1, r.pathMajor, r.pathMajor, rev)
}
if found2 {
return rev, dir2, gomod2, nil
}
if err2 == nil {
if mpath2 == "" {
return "", "", nil, fmt.Errorf("%s/%s is missing module path at revision %s", r.codeRoot, file2, rev)
}
return "", "", nil, fmt.Errorf("%s/%s has non-...%s module path %q at revision %s", r.codeRoot, file2, r.pathMajor, mpath2, rev)
}
}
// Not v2/go.mod, so it's either go.mod or nothing. Which is it?
if found1 {
// Explicit go.mod with matching major version ok.
return rev, r.codeDir, gomod1, nil
}
if err1 == nil {View on GitHub (pinned to b6b368adc5)
Solutions
- In the source repo, remove one of the conflicting go.mod files: keep either the root or the major-subdir layout, not both.
- If keeping /v2/go.mod, restore root go.mod to a v0/v1 module path.
- Tag a new revision after the cleanup and update the dependency.
Example fix
// before: repo layout // go.mod -> module example.com/m/v2 // v2/go.mod -> module example.com/m/v2 // after: choose one layout // go.mod -> module example.com/m (root, v1) // v2/go.mod -> module example.com/m/v2 (major subdir)
Defensive patterns
Strategy: validation
Validate before calling
// In the source repo, ensure exactly one go.mod declares the major version. // bash: // grep -RE '^module .+/v[0-9]+$' go.mod v*/go.mod // # exactly one match expected for a given major version // CI lint example: // test "$(grep -lE 'module .+/v2$' go.mod v2/go.mod 2>/dev/null | wc -l)" -le 1
Prevention
- Pick one major-version layout (root go.mod OR major subdirectory) and document it.
- Add a CI check that fails if two go.mod files declare the same major module path.
- When migrating to /vN subdirectories, remove the old root declaration in the same commit.
When it happens
Trigger: A repo at revision <rev> has both `<codeDir>/go.mod` declaring `module example.com/m/v2` AND `<codeDir>/v2/go.mod` declaring `module example.com/m/v2`. Both pass isMajor against pathMajor='/v2'.
Common situations: Migrating a module to a /v2 subdirectory without removing the old root go.mod's v2 declaration; botched major-version bump; tooling that auto-creates /v2/go.mod alongside an existing root file.
Related errors
- missing %s/go.mod and ...%s/go.mod at revision %s
- %s/%s is missing module path at revision %s
- %s/%s has non-...%s module path %q at revision %s
- %s is missing module path%s at revision %s
- %s has non-...%s module path %q%s at revision %s
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/6e25fe8b4829eec0.
Report an issue: GitHub.