{"record":{"id":"8bcab2b260b2f6a5","repo":"golang/go","slug":"module-paths-beginning-with-gopkg-in-must-always","errorCode":null,"errorMessage":"module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN:\n\tgo mod init %s","messagePattern":"module paths beginning with gopkg\\.in/ must always have a major version suffix in the form of \\.vN:\n\tgo mod init (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modload/init.go","lineNumber":1269,"sourceCode":"\nfunc checkModulePath(modPath string) {\n\tif err := module.CheckImportPath(modPath); err != nil {\n\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 {","sourceCodeStart":1251,"sourceCodeEnd":1287,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modload/init.go#L1251-L1287","documentation":"During 'go mod init', the supplied module path starts with 'gopkg.in/' but module.SplitPathVersion could not extract a valid .vN major-version suffix. gopkg.in paths have a special rule: they MUST carry a .vN suffix. The message embeds a suggested path from suggestGopkgIn (which appends .v1 if no major was detected).","triggerScenarios":"'go mod init gopkg.in/user/project' (no .vN) while SplitPathVersion fails. The gopkg.in branch is taken and the user is told the canonical form via the suggestion.","commonSituations":"User unfamiliar with the gopkg.in convention; copying a GitHub-style path verbatim; migrating from dep/glide which did not enforce the suffix.","solutions":["Use the suggested command printed in the error, e.g. 'go mod init gopkg.in/user/project.v1'.","Pick the major version explicitly: .v1, .v2, .v3 ... matching the library's actual major.","If you do not need gopkg.in semantics, choose a normal domain path (example.com/project).","Verify the path matches the upstream gopkg.in repository exactly."],"exampleFix":"// before\n$ go mod init gopkg.in/yaml\n// module paths beginning with gopkg.in/ must always have a major version suffix ...:\n//   go mod init gopkg.in/yaml.v1\n\n// after\n$ go mod init gopkg.in/yaml.v3","handlingStrategy":"validation","validationCode":"// Validate a gopkg.in path before 'go mod init'.\nfunc validGopkgIn(p string) error {\n    if !strings.HasPrefix(p, \"gopkg.in/\") { return nil }\n    if _, _, ok := module.SplitPathVersion(p); !ok {\n        return fmt.Errorf(\"gopkg.in path needs .vN suffix, e.g. %s.v1\", strings.TrimRight(p, \"/\"))\n    }\n    return nil\n}","typeGuard":"func isGopkgInWithMajor(p string) bool {\n    return strings.HasPrefix(p, \"gopkg.in/\") && func() bool {\n        _, _, ok := module.SplitPathVersion(p); return ok\n    }()\n}","tryCatchPattern":"out, err := exec.Command(\"go\", \"mod\", \"init\", path).CombinedOutput()\nif err != nil && bytes.Contains(out, []byte(\"gopkg.in/ must always have a major version suffix\")) {\n    // use the suggestion embedded in the error message\n    suggested := extractSuggestedPath(out) // your helper parses the 'go mod init ...' hint\n    out, err = exec.Command(\"go\", \"mod\", \"init\", suggested).CombinedOutput()\n}\nreturn err","preventionTips":["Always pass a .vN suffix for gopkg.in paths when running 'go mod init'.","Cross-check the path against the upstream gopkg.in repository URL.","Wrap 'go mod init' in a script that auto-suggests the .vN form.","Document the gopkg.in convention for your team."],"tags":["go-mod-init","gopkg-in","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"}