{"record":{"id":"ea5c1533f2ac82f0","repo":"golang/go","slug":"major-version-without-preceding-tag-must-be-v0-no","errorCode":null,"errorMessage":"major version without preceding tag must be v0, not v1","messagePattern":"major version without preceding tag must be v0, not v1","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modfetch/coderepo.go","lineNumber":740,"sourceCode":"\t//\n\t// Moreover, if we allow a pseudo-version to use any arbitrary pre-release\n\t// tag, we end up with infinitely many possible names for each commit. Each\n\t// name consumes resources in the module cache and proxies, so we want to\n\t// restrict them to a finite set under control of the module author.\n\t//\n\t// We address both of these issues by requiring the tag upon which the\n\t// pseudo-version is based to refer to some ancestor of the revision. We\n\t// prefer the highest such tag when constructing a new pseudo-version, but do\n\t// not enforce that property when resolving existing pseudo-versions: we don't\n\t// know when the parent tags were added, and the highest-tagged parent may not\n\t// have existed when the pseudo-version was first resolved.\n\tbase, err := module.PseudoVersionBase(strings.TrimSuffix(version, \"+incompatible\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\tif base == \"\" {\n\t\tif r.pseudoMajor == \"\" && semver.Major(version) == \"v1\" {\n\t\t\treturn fmt.Errorf(\"major version without preceding tag must be v0, not v1\")\n\t\t}\n\t\treturn nil\n\t} else {\n\t\tfor _, tag := range info.Tags {\n\t\t\tversionOnly := strings.TrimPrefix(tag, tagPrefix)\n\t\t\tif versionOnly == base {\n\t\t\t\t// The base version is canonical, so if the version from the tag is\n\t\t\t\t// literally equal (not just equivalent), then the tag is canonical too.\n\t\t\t\t//\n\t\t\t\t// We allow pseudo-versions to be derived from non-canonical tags on the\n\t\t\t\t// same commit, so that tags like \"v1.1.0+some-metadata\" resolve as\n\t\t\t\t// close as possible to the canonical version (\"v1.1.0\") while still\n\t\t\t\t// enforcing a total ordering (\"v1.1.1-0.[…]\" with a unique suffix).\n\t\t\t\t//\n\t\t\t\t// However, canonical tags already have a total ordering, so there is no\n\t\t\t\t// reason not to use the canonical tag directly, and we know that the\n\t\t\t\t// canonical tag must already exist because the pseudo-version is\n\t\t\t\t// derived from it. In that case, referring to the revision by a","sourceCodeStart":722,"sourceCodeEnd":758,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modfetch/coderepo.go#L722-L758","documentation":"validatePseudoVersion (coderepo.go:738-741) handles the no-preceding-tag case (empty base). For untagged repositories the first major version permitted is v0; a v1.x pseudo-version with no prior tag is rejected because v1.0.0 is conventionally the first stable release and should be expressed as a real tag, not a pseudo-version. Only when r.pseudoMajor overrides (gopkg.in-style) is a non-v0 first version allowed.","triggerScenarios":"An untagged module's first pseudo-version is requested at v1.0.0-x format (no v0.x or v1.x tag exists). The repo has never published any tag, but the requested version claims major v1.","commonSituations":"A new module that has never been tagged but whose dependency is hand-written as v1.x; misinterpreting the pseudo-version format and starting at v1 instead of v0; legacy repos migrated without preserving tags.","solutions":["Use a v0.0.0-<timestamp>-<hash> pseudo-version for untagged repos instead of v1.x.","If v1 is genuinely intended, publish a v1.0.0 tag in the source repo and depend on that.","For gopkg.in-style modules, ensure the path carries the major suffix (.v1) so pseudoMajor is set."],"exampleFix":"// before\nrequire example.com/m v1.0.0-20240101120000-e3702bed3d42\n\n// after (untagged repo must start at v0)\nrequire example.com/m v0.0.0-20240101120000-e3702bed3d42","handlingStrategy":"validation","validationCode":"// For untagged modules, never request v1.x pseudo-versions.\n// bash:\n//   git tag --list   # if empty, the module is untagged -> use v0.0.0-…\n//\n// Go: use the tooling to derive the correct major:\n//   go get example.com/m@<commit>   // toolchain emits v0.0.0-… for untagged repos","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Publish at least one v1.0.0 tag before depending on v1.x of a module.","Default to v0.0.0 pseudo-versions for never-tagged repos.","For gopkg.in modules, keep the major suffix in the path."],"tags":["go-modules","pseudo-version","major-version","vcs-tags"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}