bazelbuild/bazel · error · NumberFormatException

invalid base %d (want 2 <= base <= 36)

Error message

invalid base %d (want 2 <= base <= 36)

What it means

StarlarkInt.parse validates the requested base and rejects anything outside 2..36 with NumberFormatException('invalid base %d (want 2 <= base <= 36)'). Long.parseLong/BigInteger support exactly this range of digit alphabets, so no other base can be honored.

Source

Thrown at src/main/java/net/starlark/java/eval/StarlarkInt.java:153

        if (base == 0 || base == prefixBase) {
          base = prefixBase;
          digits = s.substring(2); // strip prefix
        }
      }
    }

    // No prefix, no base? Use decimal.
    if (digits == s && base == 0) {
      // Don't infer base when input starts with '0' due to octal/decimal ambiguity.
      if (s.length() > 1 && s.charAt(0) == '0') {
        throw new NumberFormatException(
            "cannot infer base when string begins with a 0: "
                + Starlark.repr(stringForErrors, StarlarkSemantics.DEFAULT));
      }
      base = 10;
    }
    if (base < 2 || base > 36) {
      throw new NumberFormatException(
          String.format("invalid base %d (want 2 <= base <= 36)", base));
    }

    // Do not allow Long.parseLong and new BigInteger to accept another +/- sign.
    if (digits.startsWith("+") || digits.startsWith("-")) {
      throw new NumberFormatException(
          String.format(
              "invalid base-%d literal: %s",
              base, Starlark.repr(stringForErrors, StarlarkSemantics.DEFAULT)));
    }

    StarlarkInt result;
    try {
      result = StarlarkInt.of(Long.parseLong(digits, base));
    } catch (NumberFormatException unused1) {
      try {
        result = StarlarkInt.of(new BigInteger(digits, base));
      } catch (NumberFormatException unused2) {

View on GitHub (pinned to e6e199d060)

Solutions

  1. Clamp or validate the base before calling: if 2 <= base <= 36: int(s, base).
  2. For base-64/64+ alphabets, write an explicit decoder — int() cannot do it.
  3. If you want plain decimal, pass base 10 explicitly rather than 0.

Example fix

# before
val = int(token, len(ALPHABET))  # ALPHABET has 64 chars

# after
val = decode_custom_alphabet(token)  # explicit decoder for base-64
# or, for standard bases:
val = int(token, 16) if is_hex else int(token, 10)
Defensive patterns

Strategy: validation

Validate before calling

def safe_int(s, base):
    if base != 0 and not (2 <= base <= 36):
        fail("base must be 2..36, got %d" % base)
    return int(s, base)

Prevention

When it happens

Trigger: int("11", 1), int("zz", 36+1), int(s, 0 when a base was expected but a caller passed 0 meaning decimal-with-checks — note base 0 means 'infer', not invalid), or computing a base variable that lands out of range (e.g. len(alphabet) of a custom 64-char alphabet).

Common situations: Base64-style encodings mistakenly fed to int(s, 64); off-by-one loops using base as a loop counter; passing 0 and expecting decimal (0 means auto-infer and only errors on leading-zero strings).

Related errors


AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14). Data as JSON: /api/errors/0e7b5bea8cb7cb8a. Report an issue: GitHub.