spring-projects/spring-ai · error · java.lang.IllegalArgumentException

Cannot safely convert numeric value

Error message

Cannot safely convert numeric value '{value}' to long

What it means

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.

Solutions

  1. Use double, BigDecimal, or String parameter types for values that may exceed long range or be fractional.
  2. Have the client send an integer literal within [-2^63, 2^63-1].
  3. Catch the IllegalArgumentException in the callback layer and map it to an MCP tool/prompt error response.

Example fix

// before
@McpArg long fileSize  // client sends 1.5e19
// after
@McpArg double fileSize  // or accept String and parse with validation
Defensive patterns

Strategy: try-catch

Validate before calling

boolean safeAsLong(Number n) {
    try { return new BigDecimal(n.toString()).longValueExact() >= 0; }
    catch (ArithmeticException | NumberFormatException e) { return false; }
}

Type guard

boolean isExactLong(Object v) {
    return v instanceof Number n
        && new BigDecimal(n.toString()).scale() <= 0
        && new BigDecimal(n.toString()).compareTo(BigDecimal.valueOf(Long.MAX_VALUE)) <= 0
        && new BigDecimal(n.toString()).compareTo(BigDecimal.valueOf(Long.MIN_VALUE)) >= 0;
}

Try / catch

try {
    Object result = callback.apply(exchange, request);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Cannot safely convert numeric value")) {
        return errorResponse("Argument must be an integer within long range");
    }
    throw e;
}

Prevention

When it happens

Trigger: A prompt argument such as 1.5 or 18446744073709551616 (2^64) bound to a long/Long @McpArg parameter; buildArgs -> convertArgumentValue -> toLongExact fails.

Common situations: 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.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/094e16e0cea3f63f. Report an issue: GitHub.

Appendix: source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AbstractMcpPromptMethodCallback.java:347

		// For other types, return as is and hope for the best
		return value;
	}

	private int toIntegerExact(Number value) {
		try {
			return this.toBigDecimal(value).intValueExact();
		}
		catch (ArithmeticException | NumberFormatException ex) {
			throw new IllegalArgumentException("Cannot safely convert numeric value '" + value + "' to int", ex);
		}
	}

	private long toLongExact(Number value) {
		try {
			return this.toBigDecimal(value).longValueExact();
		}
		catch (ArithmeticException | NumberFormatException ex) {
			throw new IllegalArgumentException("Cannot safely convert numeric value '" + value + "' to long", ex);
		}
	}

	private BigDecimal toBigDecimal(Number value) {
		if (value instanceof BigDecimal bigDecimal) {
			return bigDecimal;
		}
		if (value instanceof BigInteger bigInteger) {
			return new BigDecimal(bigInteger);
		}
		if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
			return BigDecimal.valueOf(value.longValue());
		}
		if (value instanceof Float || value instanceof Double) {
			// Use the exact binary floating-point value. The shorter toString()
			// representation may denote a different integer near large boundaries.
			return new BigDecimal(value.doubleValue());
		}

View on GitHub (pinned to 98a7beda4f)