golang/go · error
major version without preceding tag must be v0, not v1
Error message
major version without preceding tag must be v0, not v1
What it means
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.
Source
Thrown at src/cmd/go/internal/modfetch/coderepo.go:740
//
// Moreover, if we allow a pseudo-version to use any arbitrary pre-release
// tag, we end up with infinitely many possible names for each commit. Each
// name consumes resources in the module cache and proxies, so we want to
// restrict them to a finite set under control of the module author.
//
// We address both of these issues by requiring the tag upon which the
// pseudo-version is based to refer to some ancestor of the revision. We
// prefer the highest such tag when constructing a new pseudo-version, but do
// not enforce that property when resolving existing pseudo-versions: we don't
// know when the parent tags were added, and the highest-tagged parent may not
// have existed when the pseudo-version was first resolved.
base, err := module.PseudoVersionBase(strings.TrimSuffix(version, "+incompatible"))
if err != nil {
return err
}
if base == "" {
if r.pseudoMajor == "" && semver.Major(version) == "v1" {
return fmt.Errorf("major version without preceding tag must be v0, not v1")
}
return nil
} else {
for _, tag := range info.Tags {
versionOnly := strings.TrimPrefix(tag, tagPrefix)
if versionOnly == base {
// The base version is canonical, so if the version from the tag is
// literally equal (not just equivalent), then the tag is canonical too.
//
// We allow pseudo-versions to be derived from non-canonical tags on the
// same commit, so that tags like "v1.1.0+some-metadata" resolve as
// close as possible to the canonical version ("v1.1.0") while still
// enforcing a total ordering ("v1.1.1-0.[…]" with a unique suffix).
//
// However, canonical tags already have a total ordering, so there is no
// reason not to use the canonical tag directly, and we know that the
// canonical tag must already exist because the pseudo-version is
// derived from it. In that case, referring to the revision by aView on GitHub (pinned to b6b368adc5)
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.
Example fix
// before require example.com/m v1.0.0-20240101120000-e3702bed3d42 // after (untagged repo must start at v0) require example.com/m v0.0.0-20240101120000-e3702bed3d42
Defensive patterns
Strategy: validation
Validate before calling
// For untagged modules, never request v1.x pseudo-versions. // bash: // git tag --list # if empty, the module is untagged -> use v0.0.0-… // // Go: use the tooling to derive the correct major: // go get example.com/m@<commit> // toolchain emits v0.0.0-… for untagged repos
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- resolves to version %v (%s is not a tag)
- tag (%s) found on revision %s is already canonical, so shoul
- preceding tag (%s) not found
- not a descendent of preceding tag (%s)
- revision %s is not a descendent of preceding tag (%s)
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/ea5c1533f2ac82f0.
Report an issue: GitHub.