{"record":{"id":"61dfcb4c2ad238ea","repo":"github/copilot-sdk","slug":"expected-number-at-position-pos","errorCode":null,"errorMessage":"Expected number at position <pos>","messagePattern":"Expected number at position <pos>","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java","lineNumber":1113,"sourceCode":"                return \"(Object) null\";\n            }\n            throw new IllegalArgumentException(\"Expected null at position \" + pos);\n        }\n\n        private String parseNumber() {\n            int start = pos;\n            if (pos < input.length() && input.charAt(pos) == '-') {\n                pos++;\n            }\n            if (pos >= input.length()) {\n                throw new IllegalArgumentException(\"Expected number at position \" + start);\n            }\n            if (input.charAt(pos) == '0') {\n                pos++;\n            } else if (isDigitOneToNine(input.charAt(pos))) {\n                consumeDigits();\n            } else {\n                throw new IllegalArgumentException(\"Expected number at position \" + pos);\n            }\n            if (pos < input.length() && input.charAt(pos) == '.') {\n                pos++;\n                requireDigit(\"fraction\");\n                consumeDigits();\n            }\n            if (pos < input.length() && (input.charAt(pos) == 'e' || input.charAt(pos) == 'E')) {\n                pos++;\n                if (pos < input.length() && (input.charAt(pos) == '+' || input.charAt(pos) == '-')) {\n                    pos++;\n                }\n                requireDigit(\"exponent\");\n                consumeDigits();\n            }\n            String number = input.substring(start, pos);\n            try {\n                new java.math.BigDecimal(number);\n            } catch (NumberFormatException e) {","sourceCodeStart":1095,"sourceCodeEnd":1131,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java#L1095-L1131","documentation":"The CopilotToolProcessor contains a hand-rolled JSON tokenizer that converts tool-call argument JSON into Java expressions. While parsing a number literal, the first character must be '0' or a digit 1-9; anything else (e.g. a letter, '+', or a bare '-') makes the parser throw this IllegalArgumentException, since JSON grammar disallows numbers beginning any other way.","triggerScenarios":"Passing tool-call arguments where a numeric field starts with an invalid character: e.g. {\"count\": +1}, {\"count\": -} (lone minus reaching the number rule via a path that requires this branch), or a non-numeric token like {\"count\": abc} where a number was expected.","commonSituations":"LLM-generated tool arguments containing malformed JSON numbers, hand-written tool invocations with leading '+' or stray characters, template substitution leaving placeholder text where a number should be.","solutions":["Fix the JSON so the number starts with a digit 0-9 (use 0.5, not +0.5 or .5).","Validate/repair the argument JSON with a standard parser (e.g. Jackson) before invoking the tool.","Catch IllegalArgumentException around tool invocation and surface the position info (pos) to locate the malformed token."],"exampleFix":"// before\n{\"retries\": +3}\n// after\n{\"retries\": 3}","handlingStrategy":"validation","validationCode":"static boolean validNumberStart(String json) {\n    java.util.regex.Matcher m = java.util.regex.Pattern.compile(\"\\\\\"-?\\\\d+(\\\\.\\\\d+)?([eE][+-]?\\\\d+)?\\\\\"\").matcher(json);\n    return m.find();\n}\n// or simply: try { new com.fasterxml.jackson.databind.ObjectMapper().readTree(args); } catch (Exception e) { /* reject */ }","typeGuard":"static boolean isJsonNumberStart(String s, int i) {\n    if (i < 0 || i >= s.length()) return false;\n    char c = s.charAt(i);\n    return c == '-' || (c >= '0' && c <= '9');\n}","tryCatchPattern":"try {\n    processor.parse(args);\n} catch (IllegalArgumentException e) {\n    log.warn(\"Malformed tool args: {}\", e.getMessage());\n    return Result.rejected(args, e.getMessage());\n}","preventionTips":["Run a standard JSON parser over tool arguments before custom processing.","Never build number literals by string concatenation from user input.","Log the raw argument string whenever parsing fails so the offending token is visible."],"tags":["json","parsing","tool-arguments","java"],"backgroundTag":"json-parse-error","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}