{"record":{"id":"094e16e0cea3f63f","repo":"spring-projects/spring-ai","slug":"cannot-safely-convert-numeric-value-value-to-l","errorCode":null,"errorMessage":"Cannot safely convert numeric value '{value}' to long","messagePattern":"Cannot safely convert numeric value '(.+?)' to long","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":347,"sourceCode":"\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);\n\t\t}\n\t\tif (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {\n\t\t\treturn BigDecimal.valueOf(value.longValue());\n\t\t}\n\t\tif (value instanceof Float || value instanceof Double) {\n\t\t\t// Use the exact binary floating-point value. The shorter toString()\n\t\t\t// representation may denote a different integer near large boundaries.\n\t\t\treturn new BigDecimal(value.doubleValue());\n\t\t}","sourceCodeStart":329,"sourceCodeEnd":365,"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#L329-L365","documentation":"Analogous to the int case: converting a prompt argument to long/Long uses toLongExact, which calls BigDecimal.longValueExact() and rethrows ArithmeticException/NumberFormatException as this IllegalArgumentException when the numeric value is fractional or exceeds Long range. The framework avoids silent truncation/overflow of client-supplied numbers.","triggerScenarios":"A prompt argument such as 1.5 or 18446744073709551616 (2^64) bound to a long/Long @McpArg parameter; buildArgs -> convertArgumentValue -> toLongExact fails.","commonSituations":"Clients sending huge IDs or timestamps outside the signed 64-bit range; fractional numbers sent for long fields; JSON numbers parsed as Double then asked to be an exact long.","solutions":["Use double, BigDecimal, or String parameter types for values that may exceed long range or be fractional.","Have the client send an integer literal within [-2^63, 2^63-1].","Catch the IllegalArgumentException in the callback layer and map it to an MCP tool/prompt error response."],"exampleFix":"// before\n@McpArg long fileSize  // client sends 1.5e19\n// after\n@McpArg double fileSize  // or accept String and parse with validation","handlingStrategy":"try-catch","validationCode":"boolean safeAsLong(Number n) {\n    try { return new BigDecimal(n.toString()).longValueExact() >= 0; }\n    catch (ArithmeticException | NumberFormatException e) { return false; }\n}","typeGuard":"boolean isExactLong(Object v) {\n    return v instanceof Number n\n        && new BigDecimal(n.toString()).scale() <= 0\n        && new BigDecimal(n.toString()).compareTo(BigDecimal.valueOf(Long.MAX_VALUE)) <= 0\n        && new BigDecimal(n.toString()).compareTo(BigDecimal.valueOf(Long.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 long range\");\n    }\n    throw e;\n}","preventionTips":["Use double or String types for values that may exceed 2^63-1 (e.g. large IDs, sizes).","Instruct clients via prompt documentation to send bounded integer literals.","Prefer Long over long so nulls from missing arguments are distinguishable."],"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"}