{"record":{"id":"f6692e0d865c08d9","repo":"golang/go","slug":"not-a-descendent-of-preceding-tag-s","errorCode":null,"errorMessage":"not a descendent of preceding tag (%s)","messagePattern":"not a descendent of preceding tag \\((.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modfetch/coderepo.go","lineNumber":793,"sourceCode":"\t\t\tlastTag = tag.Name\n\t\t\tancestorFound, err = r.code.DescendsFrom(ctx, info.Name, tag.Name)\n\t\t\tif ancestorFound {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif lastTag == \"\" {\n\t\treturn fmt.Errorf(\"preceding tag (%s) not found\", base)\n\t}\n\n\tif !ancestorFound {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\trev, err := module.PseudoVersionRev(version)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"not a descendent of preceding tag (%s)\", lastTag)\n\t\t}\n\t\treturn fmt.Errorf(\"revision %s is not a descendent of preceding tag (%s)\", rev, lastTag)\n\t}\n\treturn nil\n}\n\nfunc (r *codeRepo) revToRev(rev string) string {\n\tif semver.IsValid(rev) {\n\t\tif module.IsPseudoVersion(rev) {\n\t\t\tr, _ := module.PseudoVersionRev(rev)\n\t\t\treturn r\n\t\t}\n\t\tif semver.Build(rev) == \"+incompatible\" {\n\t\t\trev = rev[:len(rev)-len(\"+incompatible\")]\n\t\t}\n\t\tif r.codeDir == \"\" {\n\t\t\treturn rev\n\t\t}","sourceCodeStart":775,"sourceCodeEnd":811,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modfetch/coderepo.go#L775-L811","documentation":"validatePseudoVersion (coderepo.go:787-794). A tag matching base was found (so lastTag is set) but r.code.DescendsFrom reported the revision is NOT a descendant of it, AND module.PseudoVersionRev failed to extract a revision from the version string. This is a secondary failure: the more specific 'revision %s is not a descendent…' message could not be produced because the rev could not be parsed.","triggerScenarios":"The pseudo-version is structurally malformed such that PseudoVersionRev returns an error, AND the ancestor check against an existing base tag failed. Rare; usually preceded by a separate syntax error.","commonSituations":"Hand-editing the pseudo-version so the rev field is unparseable; combined corruption of timestamp and rev fields; older pseudo-version formats no longer accepted by newer toolchains.","solutions":["Re-derive the pseudo-version with `go get <module>@<commit>`.","Validate the pseudo-version shape with `module.PseudoVersionRev` / `PseudoVersionTime` before recording it.","If you need a non-descendant revision, use a pseudo-version based on a tag that IS an ancestor."],"exampleFix":"// before (malformed rev field AND not a descendant of v1.2.3)\nrequire example.com/m v1.2.4-0.20240101120000-not-a-hash\n\n// after (well-formed and based on an ancestor tag)\nrequire example.com/m v1.2.3-0.20240101120000-e3702bed3d42","handlingStrategy":"validation","validationCode":"// Reject malformed pseudo-versions before recording them.\n// Go:\npackage main\nimport \"golang.org/x/mod/module\"\nfunc validate(pseudo string) error {\n    if _, err := module.PseudoVersionRev(pseudo); err != nil { return err }\n    if _, err := module.PseudoVersionTime(pseudo); err != nil { return err }\n    if _, err := module.PseudoVersionBase(pseudo); err != nil { return err }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate pseudo-versions structurally with the x/mod/module helpers before committing them.","Always derive via `go get @<commit>` rather than hand-editing.","Treat unparseable pseudo-versions as corrupt and re-derive."],"tags":["go-modules","pseudo-version","vcs-tags","validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}