{"record":{"id":"7f1018421e1c7a0e","repo":"golang/go","slug":"major-version-suffixes-must-be-in-the-form-of-vn","errorCode":null,"errorMessage":"major version suffixes must be in the form of /vN and are only allowed for v2 or later:\n\tgo mod init %s","messagePattern":"major version suffixes must be in the form of /vN and are only allowed for v2 or later:\n\tgo mod init (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modload/init.go","lineNumber":1272,"sourceCode":"\t\tif pathErr, ok := err.(*module.InvalidPathError); ok {\n\t\t\tpathErr.Kind = \"module\"\n\t\t\t// Same as build.IsLocalPath()\n\t\t\tif pathErr.Path == \".\" || pathErr.Path == \"..\" ||\n\t\t\t\tstrings.HasPrefix(pathErr.Path, \"./\") || strings.HasPrefix(pathErr.Path, \"../\") {\n\t\t\t\tpathErr.Err = errors.New(\"is a local import path\")\n\t\t\t}\n\t\t}\n\t\tbase.Fatal(err)\n\t}\n\tif err := CheckReservedModulePath(modPath); err != nil {\n\t\tbase.Fatalf(`go: invalid module path %q: `, modPath)\n\t}\n\tif _, _, ok := module.SplitPathVersion(modPath); !ok {\n\t\tif strings.HasPrefix(modPath, \"gopkg.in/\") {\n\t\t\tinvalidMajorVersionMsg := fmt.Errorf(\"module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN:\\n\\tgo mod init %s\", suggestGopkgIn(modPath))\n\t\t\tbase.Fatalf(`go: invalid module path \"%v\": %v`, modPath, invalidMajorVersionMsg)\n\t\t}\n\t\tinvalidMajorVersionMsg := fmt.Errorf(\"major version suffixes must be in the form of /vN and are only allowed for v2 or later:\\n\\tgo mod init %s\", suggestModulePath(modPath))\n\t\tbase.Fatalf(`go: invalid module path \"%v\": %v`, modPath, invalidMajorVersionMsg)\n\t}\n}\n\n// fixVersion returns a modfile.VersionFixer implemented using the Query function.\n//\n// It resolves commit hashes and branch names to versions,\n// canonicalizes versions that appeared in early vgo drafts,\n// and does nothing for versions that already appear to be canonical.\n//\n// The VersionFixer sets 'fixed' if it ever returns a non-canonical version.\nfunc fixVersion(ld *Loader, ctx context.Context, fixed *bool) modfile.VersionFixer {\n\treturn func(path, vers string) (resolved string, err error) {\n\t\tdefer func() {\n\t\t\tif err == nil && resolved != vers {\n\t\t\t\t*fixed = true\n\t\t\t}\n\t\t}()","sourceCodeStart":1254,"sourceCodeEnd":1290,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modload/init.go#L1254-L1290","documentation":"During 'go mod init', the supplied module path failed SplitPathVersion and is NOT a gopkg.in path. The non-gopkg.in rule: major-version suffixes must be /vN and are only permitted for v2+. The message includes a suggestion from suggestModulePath (it strips a malformed suffix and proposes /v2 or /vN).","triggerScenarios":"'go mod init example.com/m/v2' but SplitPathVersion fails (e.g. malformed /v token like '/version2', or '/v0', '/v1' which are not allowed), or a path with no resolvable suffix on a v2+ intent.","commonSituations":"User adds /v2 but mistypes (/V2, /v-2); user puts /v1 thinking it is required; path has trailing slash or odd characters; first-time module authors.","solutions":["Follow the suggested command printed in the error (e.g. 'go mod init example.com/m/v2').","For v0/v1 modules, omit any suffix: 'go mod init example.com/m'.","Only add /vN (N>=2) when genuinely releasing a new major version, and keep N as a plain integer.","Avoid characters that break path parsing: spaces, commas, capital V."],"exampleFix":"// before\n$ go mod init example.com/m/version2\n// major version suffixes must be in the form of /vN ...:\n//   go mod init example.com/m/v2\n\n// after\n$ go mod init example.com/m/v2","handlingStrategy":"validation","validationCode":"// Validate a non-gopkg.in module path before 'go mod init'.\nfunc validModulePath(p string) error {\n    if strings.HasPrefix(p, \"gopkg.in/\") { return nil }\n    if _, _, ok := module.SplitPathVersion(p); !ok {\n        return fmt.Errorf(\"path %s needs no suffix (v0/v1) or a /vN (N>=2) suffix\", p)\n    }\n    return nil\n}","typeGuard":"func isValidModulePathWithSuffix(p string) bool {\n    _, _, ok := module.SplitPathVersion(p); return ok\n}","tryCatchPattern":"out, err := exec.Command(\"go\", \"mod\", \"init\", path).CombinedOutput()\nif err != nil && bytes.Contains(out, []byte(\"major version suffixes must be in the form of /vN\")) {\n    suggested := extractSuggestedPath(out) // parse the embedded 'go mod init ...' hint\n    out, err = exec.Command(\"go\", \"mod\", \"init\", suggested).CombinedOutput()\n}\nreturn err","preventionTips":["For v0/v1 modules, omit any /vN suffix.","Only use /vN with N>=2, lowercase v, plain integer.","Validate the path with module.SplitPathVersion before init.","Let 'go mod init' suggest the form rather than guessing."],"tags":["go-mod-init","module-path","validation","major-version"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}