{"record":{"id":"3e9bfadf4037137d","repo":"tailscale/tailscale","slug":"parseversion-parsing-q-w","errorCode":null,"errorMessage":"parseVersion: parsing %q: %w","messagePattern":"parseVersion: parsing %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"version/mkversion/mkversion.go","lineNumber":468,"sourceCode":"\t\tpatch:       patch,\n\t\tchangeCount: changeCount,\n\t\thash:        hash,\n\t\tdate:        date,\n\t}, nil\n}\n\nfunc parseVersion(s string) (major, minor, patch int, err error) {\n\tfs := strings.Split(strings.TrimSpace(s), \".\")\n\tif len(fs) != 3 {\n\t\terr = fmt.Errorf(\"parseVersion: parsing %q: wrong number of parts: %d\", s, len(fs))\n\t\treturn\n\t}\n\tints := make([]int, 0, 3)\n\tfor _, s := range fs {\n\t\tvar i int\n\t\ti, err = strconv.Atoi(s)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"parseVersion: parsing %q: %w\", s, err)\n\t\t\treturn\n\t\t}\n\t\tints = append(ints, i)\n\t}\n\treturn ints[0], ints[1], ints[2], nil\n}\n\nfunc shortHash(hash string) string {\n\tif len(hash) < 9 {\n\t\treturn hash\n\t}\n\treturn hash[:9]\n}\n\n// dirRunner executes commands in the specified dir.\ntype dirRunner string\n\nfunc (r dirRunner) output(prog string, args ...string) (string, error) {","sourceCodeStart":450,"sourceCodeEnd":486,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/version/mkversion/mkversion.go#L450-L486","documentation":"The second parseVersion failure mode: there were exactly three dot-separated parts, but at least one is not a plain integer (strconv.Atoi failed on it). Typical culprits: a 'v' prefix ('v1.72.0'), an empty part ('1..0'), a sign, or trailing characters like '0-rc1'. Input comes from VERSION.txt or TS_VERSION_OVERRIDE.","triggerScenarios":"TS_VERSION_OVERRIDE=v1.72.0; VERSION.txt written as '1.72.x' or '1..0'; any part containing non-digits.","commonSituations":"Copying git tags (which carry the 'v') into override variables; hand-edited VERSION.txt files.","solutions":["Strip the 'v' prefix and any pre-release suffix before setting TS_VERSION_OVERRIDE","Correct VERSION.txt so every part is digits only","Add a guard in your release script: `[[ $TS_VERSION_OVERRIDE =~ ^[0-9]+\\.[0-9]+\\.[0-9]+$ ]]`"],"exampleFix":"# before\nexport TS_VERSION_OVERRIDE=v1.72.0  # 'v1' is not an int\n\n# after\nexport TS_VERSION_OVERRIDE=1.72.0","handlingStrategy":"validation","validationCode":"// Reject versions whose parts are not plain integers.\nvar strictVersion = regexp.MustCompile(`^\\d+\\.\\d+\\.\\d+$`)\nif o := os.Getenv(\"TS_VERSION_OVERRIDE\"); o != \"\" && !strictVersion.MatchString(o) {\n\tlog.Fatalf(\"TS_VERSION_OVERRIDE must match \\\\(major.minor.patch\\\\) digits only, got %q\", o)\n}","typeGuard":"func isNonNumericPartError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"parseVersion: parsing\") && !strings.Contains(err.Error(), \"wrong number of parts\")\n}","tryCatchPattern":"v, err := mkversion.InfoFrom(dir)\nif err != nil {\n\tif isNonNumericPartError(err) {\n\t\treturn fmt.Errorf(\"strip 'v' prefix and suffixes from the version string: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Never pass git tags verbatim; strip the leading 'v'","Use `echo ${TAG#v}` style normalization in release scripts"],"tags":["version-parsing","validation","build-tooling"],"backgroundTag":"invalid-version-string","analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}