{"record":{"id":"6e25fe8b4829eec0","repo":"golang/go","slug":"s-s-and-s-go-mod-both-have-s-module-path","errorCode":null,"errorMessage":"%s/%s and ...%s/go.mod both have ...%s module paths at revision %s","messagePattern":"(.+?)/(.+?) and \\.\\.\\.(.+?)/go\\.mod both have \\.\\.\\.(.+?) module paths at revision (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modfetch/coderepo.go","lineNumber":869,"sourceCode":"\tif r.pathMajor != \"\" && r.codeRoot != r.modPath && !strings.HasPrefix(r.pathMajor, \".\") {\n\t\t// Suppose pathMajor is \"/v2\".\n\t\t// Either go.mod should claim v2 and v2/go.mod should not exist,\n\t\t// or v2/go.mod should exist and claim v2. Not both.\n\t\t// Note that we don't check the full path, just the major suffix,\n\t\t// because of replacement modules. This might be a fork of\n\t\t// the real module, found at a different path, usable only in\n\t\t// a replace directive.\n\t\tdir2 := path.Join(r.codeDir, r.pathMajor[1:])\n\t\tfile2 = path.Join(dir2, \"go.mod\")\n\t\tgomod2, err2 := r.code.ReadFile(ctx, rev, file2, codehost.MaxGoMod)\n\t\tif err2 != nil && !os.IsNotExist(err2) {\n\t\t\treturn \"\", \"\", nil, fmt.Errorf(\"reading %s/%s at revision %s: %v\", r.codeRoot, file2, rev, err2)\n\t\t}\n\t\tmpath2 := modfile.ModulePath(gomod2)\n\t\tfound2 := err2 == nil && isMajor(mpath2, r.pathMajor)\n\n\t\tif found1 && found2 {\n\t\t\treturn \"\", \"\", 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)\n\t\t}\n\t\tif found2 {\n\t\t\treturn rev, dir2, gomod2, nil\n\t\t}\n\t\tif err2 == nil {\n\t\t\tif mpath2 == \"\" {\n\t\t\t\treturn \"\", \"\", nil, fmt.Errorf(\"%s/%s is missing module path at revision %s\", r.codeRoot, file2, rev)\n\t\t\t}\n\t\t\treturn \"\", \"\", nil, fmt.Errorf(\"%s/%s has non-...%s module path %q at revision %s\", r.codeRoot, file2, r.pathMajor, mpath2, rev)\n\t\t}\n\t}\n\n\t// Not v2/go.mod, so it's either go.mod or nothing. Which is it?\n\tif found1 {\n\t\t// Explicit go.mod with matching major version ok.\n\t\treturn rev, r.codeDir, gomod1, nil\n\t}\n\tif err1 == nil {","sourceCodeStart":851,"sourceCodeEnd":887,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modfetch/coderepo.go#L851-L887","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","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."],"exampleFix":"// before: repo layout\n//   go.mod      -> module example.com/m/v2\n//   v2/go.mod   -> module example.com/m/v2\n\n// after: choose one layout\n//   go.mod      -> module example.com/m      (root, v1)\n//   v2/go.mod   -> module example.com/m/v2   (major subdir)","handlingStrategy":"validation","validationCode":"// In the source repo, ensure exactly one go.mod declares the major version.\n// bash:\n//   grep -RE '^module .+/v[0-9]+$' go.mod v*/go.mod\n//   # exactly one match expected for a given major version\n// CI lint example:\n//   test \"$(grep -lE 'module .+/v2$' go.mod v2/go.mod 2>/dev/null | wc -l)\" -le 1","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["go-modules","go-mod","major-version","repository-layout"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}