{"record":{"id":"4552cc7a05e6f6a1","repo":"spring-projects/spring-ai","slug":"cannot-safely-convert-numeric-value-value-to-i","errorCode":null,"errorMessage":"Cannot safely convert numeric value '{value}' to int","messagePattern":"Cannot safely convert numeric value '(.+?)' to int","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AbstractMcpPromptMethodCallback.java","lineNumber":338,"sourceCode":"\t\telse if (targetType == Boolean.class || targetType == boolean.class) {\n\t\t\tif (value instanceof Boolean) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn Boolean.parseBoolean(value.toString());\n\t\t\t}\n\t\t}\n\n\t\t// For other types, return as is and hope for the best\n\t\treturn value;\n\t}\n\n\tprivate int toIntegerExact(Number value) {\n\t\ttry {\n\t\t\treturn this.toBigDecimal(value).intValueExact();\n\t\t}\n\t\tcatch (ArithmeticException | NumberFormatException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Cannot safely convert numeric value '\" + value + \"' to int\", ex);\n\t\t}\n\t}\n\n\tprivate long toLongExact(Number value) {\n\t\ttry {\n\t\t\treturn this.toBigDecimal(value).longValueExact();\n\t\t}\n\t\tcatch (ArithmeticException | NumberFormatException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Cannot safely convert numeric value '\" + value + \"' to long\", ex);\n\t\t}\n\t}\n\n\tprivate BigDecimal toBigDecimal(Number value) {\n\t\tif (value instanceof BigDecimal bigDecimal) {\n\t\t\treturn bigDecimal;\n\t\t}\n\t\tif (value instanceof BigInteger bigInteger) {\n\t\t\treturn new BigDecimal(bigInteger);","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AbstractMcpPromptMethodCallback.java#L320-L356","documentation":"When binding prompt arguments to an int/Integer parameter, convertArgumentValue delegates to toIntegerExact, which converts the Number via BigDecimal.intValueExact(). If the value is fractional, out of int range, or unrepresentable, intValueExact throws ArithmeticException (or NumberFormatException), rethrown as this IllegalArgumentException. The library refuses lossy conversions rather than silently truncating.","triggerScenarios":"A client sends a prompt argument like 3.5, 1e30, or 2147483648 for a method parameter typed int/Integer with @McpArg; buildArgs -> convertArgumentValue -> toIntegerExact throws at invocation time.","commonSituations":"LLM clients emitting float-typed numbers for integer fields (JSON 3.0 vs 3); client sending a count/limit exceeding Integer.MAX_VALUE; decimal input like 0.5 for an int parameter.","solutions":["Change the parameter type to long or double if the value can legitimately be larger or fractional.","Validate/coerce the incoming argument client-side (or in a wrapper method) before it reaches the handler.","Catch IllegalArgumentException around the callback invocation and return a descriptive MCP error to the client asking for an integer in range."],"exampleFix":"// before\n@McpArg int maxResults\n// after\n@McpArg long maxResults  // or validate: if (d != Math.floor(d) || d > Integer.MAX_VALUE) throw ...","handlingStrategy":"try-catch","validationCode":"boolean safeAsInt(Number n) {\n    try { return new BigDecimal(n.toString()).intValueExact() >= 0; }\n    catch (ArithmeticException | NumberFormatException e) { return false; }\n}","typeGuard":"boolean isExactInt(Object v) {\n    return v instanceof Number n\n        && new BigDecimal(n.toString()).scale() <= 0\n        && new BigDecimal(n.toString()).compareTo(BigDecimal.valueOf(Integer.MAX_VALUE)) <= 0\n        && new BigDecimal(n.toString()).compareTo(BigDecimal.valueOf(Integer.MIN_VALUE)) >= 0;\n}","tryCatchPattern":"try {\n    Object result = callback.apply(exchange, request);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Cannot safely convert numeric value\")) {\n        return errorResponse(\"Argument must be an integer within int range\");\n    }\n    throw e;\n}","preventionTips":["Type numeric prompt arguments as long or double when range/fraction is possible.","Document expected ranges in the prompt description so LLM clients send valid integers.","Validate arguments in the handler before arithmetic use."],"tags":["mcp","numeric-conversion","argument-binding","overflow"],"backgroundTag":"value-out-of-range","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}