{"record":{"id":"6cb2b4a847e428c3","repo":"golang/go","slug":"non-semver-module-version-q","errorCode":null,"errorMessage":"non-semver module version %q","messagePattern":"non-semver module version %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modfetch/cache.go","lineNumber":57,"sourceCode":"\t\treturn \"\", err\n\t}\n\tenc, err := module.EscapePath(path)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn filepath.Join(cfg.GOMODCACHE, \"cache/download\", enc, \"/@v\"), nil\n}\n\nfunc CachePath(ctx context.Context, m module.Version, suffix string) (string, error) {\n\tif gover.IsToolchain(m.Path) {\n\t\treturn \"\", ErrToolchain\n\t}\n\tdir, err := cacheDir(ctx, m.Path)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif !gover.ModIsValid(m.Path, m.Version) {\n\t\treturn \"\", fmt.Errorf(\"non-semver module version %q\", m.Version)\n\t}\n\tif module.CanonicalVersion(m.Version) != m.Version {\n\t\treturn \"\", fmt.Errorf(\"non-canonical module version %q\", m.Version)\n\t}\n\tencVer, err := module.EscapeVersion(m.Version)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn filepath.Join(dir, encVer+\".\"+suffix), nil\n}\n\n// DownloadDir returns the directory to which m should have been downloaded.\n// An error will be returned if the module path or version cannot be escaped.\n// An error satisfying errors.Is(err, fs.ErrNotExist) will be returned\n// along with the directory if the directory does not exist or if the directory\n// is not completely populated.\nfunc DownloadDir(ctx context.Context, m module.Version) (string, error) {\n\tif gover.IsToolchain(m.Path) {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modfetch/cache.go#L39-L75","documentation":"Thrown by `modfetch.CachePath` when `gover.ModIsValid(path, version)` returns false for the module path/version combination. ModIsValid checks that the version is syntactically valid semver (or a recognized non-semver form for certain paths). A non-semver version cannot be encoded into the cache directory structure. This is distinct from canonicality — it's about basic structural validity.","triggerScenarios":"Calling `modfetch.CachePath(ctx, module.Version{Path: path, Version: version}, suffix)` with a version like 'latest', 'HEAD', a raw commit hash not in recognized form, or a malformed semver string. This is an internal API called during module download/lookup when the version isn't a valid module version.","commonSituations":"Internal go command bugs; calling modfetch APIs directly with unvalidated versions; module resolution producing an invalid version string; race conditions during version resolution.","solutions":["Validate the version with gover.ModIsValid before calling CachePath","Resolve symbolic versions (like 'latest') to concrete semver before passing to cache APIs","Use the higher-level modload/modfetch APIs that handle version resolution automatically"],"exampleFix":"// before\npath, err := modfetch.CachePath(ctx, module.Version{Path: m, Version: \"latest\"}, \"zip\")\n// after\ninfo, err := modfetch.Lookup(ctx, m).Stat(ctx, \"latest\")\npath, err := modfetch.CachePath(ctx, module.Version{Path: m, Version: info.Version}, \"zip\")","handlingStrategy":"validation","validationCode":"import \"golang.org/x/mod/gover\"\n\nfunc safeCachePath(ctx context.Context, m module.Version, suffix string) (string, error) {\n    if !gover.ModIsValid(m.Path, m.Version) {\n        return \"\", fmt.Errorf(\"invalid version %q for path %q\", m.Version, m.Path)\n    }\n    return modfetch.CachePath(ctx, m, suffix)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always resolve symbolic versions via Stat() before calling cache APIs","Validate versions with gover.ModIsValid before passing to modfetch internals","Prefer high-level modload APIs over direct modfetch calls"],"tags":["go","go-mod","version","validation","internal-api"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}