github/copilot-sdk · error · IllegalArgumentException

Number cannot be represented at position

Error message

Number cannot be represented at position <start>: <number>

What it means

After lexing a numeric token, CopilotToolProcessor validates it by constructing a java.math.BigDecimal from the substring. If BigDecimal rejects the text (NumberFormatException), the parser rethrows IllegalArgumentException stating the number cannot be represented, wrapping the original exception. This guards against malformed numeric literals that slip past the grammar check.

Solutions

  1. Inspect the quoted number in the message and correct it to a valid JSON numeric literal.
  2. Re-send the tool call with the argument value regenerated as a plain decimal/exponent form.
  3. Catch IllegalArgumentException (getCause() is NumberFormatException) and fall back to a JSON repair pass before parsing.

Example fix

// before
{"amount": 1_000}
// after
{"amount": 1000}
Defensive patterns

Strategy: try-catch

Validate before calling

static boolean isRepresentableNumber(String token) {
    try { new java.math.BigDecimal(token); return true; }
    catch (NumberFormatException e) { return false; }
}

Type guard

static java.math.BigDecimal asBigDecimalOrNull(String token) {
    try { return new java.math.BigDecimal(token.trim()); }
    catch (NumberFormatException e) { return null; }
}

Try / catch

try {
    processor.parse(args);
} catch (IllegalArgumentException e) {
    if (e.getCause() instanceof NumberFormatException nfe) {
        // retry after sanitizing the numeric token named in e.getMessage()
    }
    throw e;
}

Prevention

When it happens

Trigger: A number token that passed the start-character check but is not BigDecimal-parseable, e.g. an empty token, or a value with characters the grammar accidentally allowed. Wraps NumberFormatException from new java.math.BigDecimal(number) at position start.

Common situations: Exotic or malformed numeric literals in LLM tool-call output, truncated JSON from a stream cut mid-number, locale-independent formatting issues in generated arguments.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/46cfc192f7331de9. Report an issue: GitHub.

Appendix: source

Thrown at java/sdk/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java:1132

            }
            if (pos < input.length() && input.charAt(pos) == '.') {
                pos++;
                requireDigit("fraction");
                consumeDigits();
            }
            if (pos < input.length() && (input.charAt(pos) == 'e' || input.charAt(pos) == 'E')) {
                pos++;
                if (pos < input.length() && (input.charAt(pos) == '+' || input.charAt(pos) == '-')) {
                    pos++;
                }
                requireDigit("exponent");
                consumeDigits();
            }
            String number = input.substring(start, pos);
            try {
                new java.math.BigDecimal(number);
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Number cannot be represented at position " + start + ": " + number,
                        e);
            }
            return "new java.math.BigDecimal(\"" + number + "\")";
        }

        private void requireDigit(String part) {
            if (pos >= input.length() || !isAsciiDigit(input.charAt(pos))) {
                throw new IllegalArgumentException("Expected digit in number " + part + " at position " + pos);
            }
        }

        private void consumeDigits() {
            while (pos < input.length() && isAsciiDigit(input.charAt(pos))) {
                pos++;
            }
        }

        private boolean isAsciiDigit(char c) {

View on GitHub (pinned to cd8cf15dc3)