bazelbuild/bazel · error · NumberFormatException
cannot infer base when string begins with a 0: %s
Error message
cannot infer base when string begins with a 0: %s
What it means
StarlarkInt.parse cannot choose a base when the caller passes base=0 ('auto') and the digit string begins with '0' (and is longer than one char). A leading 0 is ambiguous between octal (0755) and decimal-with-padding (0123); Starlark (unlike Python's int, which defaults to decimal) refuses to guess and throws NumberFormatException with this message. Note the 0x/0o/0b prefixes are handled earlier; this path is for unprefixed strings.
Source
Thrown at src/main/java/net/starlark/java/eval/StarlarkInt.java:146
prefixBase = 2;
} else if (c == 'o' || c == 'O') {
prefixBase = 8;
} else if (c == 'x' || c == 'X') {
prefixBase = 16;
}
if (prefixBase != 0) {
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)));
}
View on GitHub (pinned to e6e199d060)
Solutions
- Strip leading zeros before converting: int(s.lstrip("0") or "0").
- Pass the base explicitly when the value is octal: int("0755", 8).
- Change the producer to emit unpadded decimal strings.
Example fix
# before
mode = int("0644")
# after
mode = int("0644", 8) # if octal was intended
# or
mode = int("0644".lstrip("0") or "0") # if decimal 644 was intended Defensive patterns
Strategy: validation
Validate before calling
def parse_decimal(s):
s = s.strip()
if len(s) > 1 and s.startswith("0") and not s.startswith("0x") and not s.startswith("0o") and not s.startswith("0b"):
s = s.lstrip("0") or "0" # zero-padded decimal
return int(s, 10) Type guard
def has_leading_zero_ambiguity(s):
return len(s) > 1 and s[0] == "0" and s[1] not in "xob" Prevention
- Never rely on int() accepting zero-padded strings; normalize first.
- Pass an explicit base (8) for octal permission-style strings.
When it happens
Trigger: int("0123"), int("0755"), int("00") — any call with base omitted (base defaults to 10 only after this check; base=0/auto with leading-zero digits). Commonly hit when porting Python int("0755") code.
Common situations: Parsing zero-padded numbers from fixed-width formats (timestamps '0930', zip codes, permissions '0644', IDs with leading zeros); Python-to-Starlark port assuming int() strips leading zeros.
Related errors
- empty string
- invalid base-%d literal: %s
- invalid base %d (want 2 <= base <= 36)
- This converter doesn't support Starlark reversal.
- Invalid options syntax: %s Note: Negative target patterns ca
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/64f4fa855b5923e0.
Report an issue: GitHub.