browsh-org/browsh · error

VersionOrdinal: invalid version

Error message

VersionOrdinal: invalid version

What it means

versionOrdinal converts a dotted Firefox version string into a comparable ordinal by appending bytes and incrementing separators. When a numeric segment exceeds 255 (or the string is otherwise malformed such that the running byte value would overflow maxByte), it panics with 'VersionOrdinal: invalid version'. It guards the algorithm's byte-per-segment assumption.

Source

Thrown at interfacer/src/browsh/firefox.go:150

	vo := make([]byte, 0, len(version)+8)
	j := -1
	for i := 0; i < len(version); i++ {
		b := version[i]
		if '0' > b || b > '9' {
			vo = append(vo, b)
			j = -1
			continue
		}
		if j == -1 {
			vo = append(vo, 0x00)
			j = len(vo) - 1
		}
		if vo[j] == 1 && vo[j+1] == '0' {
			vo[j+1] = b
			continue
		}
		if vo[j]+1 > maxByte {
			panic("VersionOrdinal: invalid version")
		}
		vo = append(vo, b)
		vo[j]++
	}
	return string(vo)
}

// Start Firefox via the `web-ext` CLI tool. This is for development and testing,
// because I haven't been able to recreate the way `web-ext` injects an unsigned
// extension.
func startWERFirefox() {
	slog.Info("Attempting to start headless Firefox with `web-ext`")
	if IsConnectedToWebExtension {
		Shutdown(errors.New("There appears to already be an existing Web Extension connection"))
	}
	checkIfFirefoxIsAlreadyRunning()
	rootDir := Shell("git rev-parse --show-toplevel")
	args := []string{

View on GitHub (pinned to 499ef386d4)

Solutions

  1. Check the Firefox version string browsh detected (log output) for an unexpected format and correct the source of the version (registry value, `firefox --version`).
  2. Upgrade browsh to a release that handles newer version formats.
  3. Patch/replace versionOrdinal to parse numeric segments into integers instead of single bytes.
  4. Pin a Firefox version whose format the current algorithm supports.

Example fix

// before
if vo[j]+1 > maxByte {
    panic("VersionOrdinal: invalid version")
}
// after
if seg, err := strconv.Atoi(part); err == nil && seg > 255 {
    // compare numerically instead of byte ordinal
    return compareNumericSegments(parts, other)
}
Defensive patterns

Strategy: validation

Validate before calling

// check version string before browsh processes it
function isSafeVersion(v) {
  return /^\d+(\.\d+)*$/.test(v) && v.split('.').every(n => Number(n) <= 255);
}
if (!isSafeVersion(firefoxVersion)) console.warn('Version unsupported by ordinal comparison');

Type guard

function isValidVersionString(v) {
  return typeof v === 'string' && /^\d+(\.\d+)*$/.test(v) &&
    v.split('.').every(seg => parseInt(seg, 10) >= 0 && parseInt(seg, 10) <= 255);
}

Prevention

When it happens

Trigger: ensureFirefoxVersion passes a version string whose segment value exceeds 255, or a non-numeric/unexpectedly formatted version string that corrupts the ordinal computation, into versionOrdinal.

Common situations: A future Firefox version with a major number above 255 (unlikely but possible) or an unusual segment; a nightly/beta or fork reporting versions like '100.0.1' plus unexpected suffixes; a registry CurrentVersion value with unexpected format on Windows.

Related errors


AI-assisted analysis of browsh-org/browsh@499ef386d4 (2026-09-02). Data as JSON: /api/errors/323f0eebb4411f54. Report an issue: GitHub.