github/copilot-sdk · error · IllegalArgumentException
Expected digit in number
Error message
Expected digit in number <part> at position <pos>
What it means
The JSON number parser in CopilotToolProcessor calls requireDigit(part) after seeing '.' or 'e'/'E' to demand at least one digit in the fraction or exponent part. If the input ends or a non-digit follows, it throws this IllegalArgumentException naming which part ('fraction' or 'exponent') was missing a digit. JSON forbids literals like 1. or 1e.
Solutions
- Complete the number: change 1. to 1.0 and 1e to 1e0 (or drop the marker).
- Ensure the JSON source is complete before parsing (check stream/string termination).
- Catch IllegalArgumentException and use the pos/part detail to report precisely where the number is truncated.
Example fix
// before
{"threshold": 0.}
// after
{"threshold": 0.0} Defensive patterns
Strategy: validation
Validate before calling
static boolean hasCompleteNumbers(String json) {
return json.matches(".*\\d+(\\.\\d+)?([eE][+-]?\\d+)?.*")
&& !java.util.regex.Pattern.compile("\\d\\.([^\\d]|$)|\\d[eE]([^\\d]|$)").matcher(json).find();
} Type guard
static boolean completeNumberAt(String s, int i) {
// after '.' or 'e'/'E' there must be at least one digit
return i + 1 < s.length() && Character.isDigit(s.charAt(i + 1));
} Try / catch
try {
processor.parse(args);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Expected digit in number")) {
// input likely truncated — request the remainder before retrying
}
throw e;
} Prevention
- Only parse JSON after the producing stream has fully terminated.
- Reject human-formatted numbers like "5." during argument generation.
- Validate with a reference JSON parser before invoking the tool processor.
When it happens
Trigger: Arguments containing number literals with a dangling decimal point ("1.") or dangling exponent marker ("1e", "1e-") — the character after the marker is missing or not a digit.
Common situations: Truncated LLM output (stream ended mid-number), copy-paste of numbers formatted for humans (e.g. "5." at end of a sentence), template generation bugs.
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
- Number cannot be represented at position
- Unexpected end of JSON
- Unexpected trailing content at position
- Unescaped control character at position <pos-1>
- Unterminated string escape at position
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/93e715f40aa88919.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java:1140
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) {
return c >= '0' && c <= '9';
}
private boolean isDigitOneToNine(char c) {
return c >= '1' && c <= '9';
}
private void skipWhitespace() {View on GitHub (pinned to cd8cf15dc3)