tailscale/tailscale · error

parseVersion: parsing %q: %w

Error message

parseVersion: parsing %q: %w

What it means

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.

Source

Thrown at version/mkversion/mkversion.go:468

		patch:       patch,
		changeCount: changeCount,
		hash:        hash,
		date:        date,
	}, nil
}

func parseVersion(s string) (major, minor, patch int, err error) {
	fs := strings.Split(strings.TrimSpace(s), ".")
	if len(fs) != 3 {
		err = fmt.Errorf("parseVersion: parsing %q: wrong number of parts: %d", s, len(fs))
		return
	}
	ints := make([]int, 0, 3)
	for _, s := range fs {
		var i int
		i, err = strconv.Atoi(s)
		if err != nil {
			err = fmt.Errorf("parseVersion: parsing %q: %w", s, err)
			return
		}
		ints = append(ints, i)
	}
	return ints[0], ints[1], ints[2], nil
}

func shortHash(hash string) string {
	if len(hash) < 9 {
		return hash
	}
	return hash[:9]
}

// dirRunner executes commands in the specified dir.
type dirRunner string

func (r dirRunner) output(prog string, args ...string) (string, error) {

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Strip the 'v' prefix and any pre-release suffix before setting TS_VERSION_OVERRIDE
  2. Correct VERSION.txt so every part is digits only
  3. Add a guard in your release script: `[[ $TS_VERSION_OVERRIDE =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]`

Example fix

# before
export TS_VERSION_OVERRIDE=v1.72.0  # 'v1' is not an int

# after
export TS_VERSION_OVERRIDE=1.72.0
Defensive patterns

Strategy: validation

Validate before calling

// Reject versions whose parts are not plain integers.
var strictVersion = regexp.MustCompile(`^\d+\.\d+\.\d+$`)
if o := os.Getenv("TS_VERSION_OVERRIDE"); o != "" && !strictVersion.MatchString(o) {
	log.Fatalf("TS_VERSION_OVERRIDE must match \\(major.minor.patch\\) digits only, got %q", o)
}

Type guard

func isNonNumericPartError(err error) bool {
	return err != nil && strings.Contains(err.Error(), "parseVersion: parsing") && !strings.Contains(err.Error(), "wrong number of parts")
}

Try / catch

v, err := mkversion.InfoFrom(dir)
if err != nil {
	if isNonNumericPartError(err) {
		return fmt.Errorf("strip 'v' prefix and suffixes from the version string: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: TS_VERSION_OVERRIDE=v1.72.0; VERSION.txt written as '1.72.x' or '1..0'; any part containing non-digits.

Common situations: Copying git tags (which carry the 'v') into override variables; hand-edited VERSION.txt files.

Related errors


AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18). Data as JSON: /api/errors/3e9bfadf4037137d. Report an issue: GitHub.