apache/dubbo · error · ClassCastException
Number expected to be integer: ${d}
Error message
Number expected to be integer: ${d} What it means
Thrown by AbstractJsonUtilImpl.getNumberAsInteger(Map,String) when obj contains key, the value is a Double, but its integral cast loses precision — i.e. d.intValue() != d. This guards against silently truncating a fractional value like 3.14 into 3. It is a ClassCastException (a type-shape mismatch) naming the offending Double. Only the Double branch can reach it; String values go through Integer.parseInt.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/AbstractJsonUtilImpl.java:153
}
/**
* Gets a number from an object for the given key, casted to an integer. If the key is not
* present, this returns null. If the value does not represent an integer, throws an exception.
*/
@Override
public Integer getNumberAsInteger(Map<String, ?> obj, String key) {
assert obj != null;
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (value instanceof Double) {
Double d = (Double) value;
int i = d.intValue();
if (i != d) {
throw new ClassCastException("Number expected to be integer: " + d);
}
return i;
}
if (value instanceof String) {
try {
return Integer.parseInt((String) value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' is not an integer", value, key));
}
}
throw new IllegalArgumentException(String.format("value '%s' for key '%s' is not an integer", value, key));
}
/**
* Gets a number from an object for the given key, casted to an long. If the key is not
* present, this returns null. If the value does not represent a long integer, throws an
* exception.View on GitHub (pinned to 3a3043227f)
Solutions
- If a fractional value is a data error, fix the upstream producer to emit whole numbers.
- If truncation/rounding is acceptable, pre-round the Double: Math.round(d) or (int) Math.rint(d), then call getNumberAsInteger or read it directly.
- Switch to getNumberAsDouble if the field is genuinely non-integral.
- Catch ClassCastException and treat fractional values as a validation error.
Example fix
// before
Integer n = jsonUtil.getNumberAsInteger(obj, "qty"); // qty = 3.7
// after - round explicitly
Object raw = obj.get("qty");
Integer n = (raw instanceof Double) ? (int) Math.round((Double) raw) : jsonUtil.getNumberAsInteger(obj, "qty"); Defensive patterns
Strategy: type-guard
Validate before calling
Object raw = obj.get(key);
if (raw instanceof Double) {
double d = (Double) raw;
if (d != Math.rint(d)) {
// fractional; decide rounding policy before calling getNumberAsInteger
return (int) Math.round(d);
}
}
return jsonUtil.getNumberAsInteger(obj, key); Type guard
private static boolean isWholeDouble(Object value) {
if (!(value instanceof Double)) return value instanceof String;
double d = (Double) value;
return d == Math.rint(d);
} Try / catch
try {
return jsonUtil.getNumberAsInteger(obj, key);
} catch (ClassCastException e) {
Object raw = obj.get(key);
if (raw instanceof Double) return (int) Math.round((Double) raw); // recover
throw e;
} Prevention
- Round fractional Doubles (Math.round) before reading them as integers.
- Watch for floating accumulation error that makes whole values look fractional.
- If the field is genuinely fractional, use getNumberAsDouble instead.
When it happens
Trigger: jsonUtil.getNumberAsInteger(obj, key) where obj.get(key) is a Double with a non-zero fractional part, e.g. 3.5, 1.1, -2.9. Whole-valued doubles (3.0) pass; anything off-integer throws.
Common situations: A JSON field decoded as Double (3.0-ish backend) that occasionally carries a fractional part; a ratio/percentage mistakenly read as a count; a Float-typed upstream value widened to a fractional Double; a computed value that should be integral but accumulated floating error (e.g. 4.0000001).
Related errors
- Number expected to be long: ${d}
- value '%s' for key '%s' in '%s' is not List
- value '%s' for key '%s' in '%s' is not object
- value '%s' for key '%s' is not a double
- value '%s' for key '%s' in '%s' is not a number
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/330c02d85828cea8.
Report an issue: GitHub.