{"record":{"id":"d9b18a792b720474","repo":"hibernate/hibernate-orm","slug":"unable-to-coerce-double-value-s-to-integer-not","errorCode":null,"errorMessage":"Unable to coerce Double value `%s` to Integer: not a whole number","messagePattern":"Unable to coerce Double value `(.+?)` to Integer: not a whole number","errorType":"exception","errorClass":"CoercionException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CoercionHelper.java","lineNumber":234,"sourceCode":"\tpublic static Short toShort(BigDecimal value) {\n\t\treturn coerceWrappingError( value::shortValueExact );\n\t}\n\n\tpublic static Integer toInteger(Byte value) {\n\t\treturn value.intValue();\n\t}\n\n\tpublic static Integer toInteger(Short value) {\n\t\treturn value.intValue();\n\t}\n\n\tpublic static Integer toInteger(Long value) {\n\t\treturn coerceWrappingError( () -> Math.toIntExact( value ) );\n\t}\n\n\tpublic static Integer toInteger(Double doubleValue) {\n\t\tif ( ! isWholeNumber( doubleValue ) ) {\n\t\t\tthrow new CoercionException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\"Unable to coerce Double value `%s` to Integer: not a whole number\",\n\t\t\t\t\t\t\tdoubleValue\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\treturn toInteger( doubleValue.longValue() );\n\t}\n\n\tpublic static Integer toInteger(Float floatValue) {\n\t\tif ( ! isWholeNumber( floatValue ) ) {\n\t\t\tthrow new CoercionException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\"Unable to coerce Float value `%s` to Integer: not a whole number\",\n\t\t\t\t\t\t\tfloatValue","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CoercionHelper.java#L216-L252","documentation":"Hibernate throws this CoercionException when a Double with a fractional part must be coerced to Integer. CoercionHelper.toInteger(Double) rejects non-whole values via isWholeNumber before converting through the Long path. It is reached from IntegerJavaType.coerce when a Double value is supplied to an Integer-mapped attribute — the most commonly hit case of the family, since so many pipelines hand back Double for numeric data.","triggerScenarios":"`IntegerJavaType.coerce(2.75)` — assigning a Double to an Integer/int entity field through a Number/Object-typed setter, `setParameter(\"n\", 10.5)` bound against an Integer path, or HQL/Criteria arithmetic (`avg(...)`, `/` division) yielding Double results assigned/compared into INTEGER-mapped attributes.","commonSituations":"JSON APIs (Jackson/Gson) deserializing numeric fields as Double into DTOs copied onto Integer entity fields; computed averages or ratios stored into INT columns; JavaScript/Node frontends sending floats for integer fields; Elasticsearch/NoSQL sources returning all numbers as doubles; refactor of a Double attribute to Integer while old data or writers still emit fractions.","solutions":["Fix the producer/consumer types: make DTO fields Integer, or configure the deserializer (e.g. Jackson `ACCEPT_FLOAT_AS_INT` is disabled by default — enable it only if truncation is acceptable, better: fix payloads).","Round explicitly in your code when truncation is the agreed semantic: `Math.round`, `intValue()` after a whole-number check.","Store fractional values in DOUBLE/DECIMAL columns instead of INTEGER.","Validate whole-number-ness of incoming Numbers at the API boundary before mapping onto entities."],"exampleFix":"// before\nMap<String,Object> dto = jsonParser.parse(payload); // price: 19.99 as Double\norder.setUnits(dto.get(\"units\"));                  // Integer 'units' -> \"not a whole number\"\n\n// after\nObject raw = dto.get(\"units\");\nif (raw instanceof Double d && d != Math.rint(d)) throw new IllegalArgumentException(\"units must be whole: \" + d);\norder.setUnits(((Number) raw).intValue());\n// or fix the API contract to send integers","handlingStrategy":"validation","validationCode":"Object raw = payload.get(\"units\");\nif (raw instanceof Double d && d != Math.rint(d)) {\n    throw new IllegalArgumentException(\"units must be a whole number: \" + d);\n}\norder.setUnits(((Number) raw).intValue());","typeGuard":"static boolean isWholeDouble(Object o) { return o instanceof Double d && d == Math.rint(d) && !d.isNaN(); }","tryCatchPattern":"try { session.persist(order); } catch (CoercionException e) { throw new BadRequestException(\"whole-number field received fraction: \" + e.getMessage(), e); }","preventionTips":["Type JSON DTO numeric fields concretely (Integer) instead of Object/Number.","Do not enable Jackson's ACCEPT_FLOAT_AS_INT globally without agreeing truncation semantics.","Validate whole-number-ness in the web layer for integer endpoints.","In HQL, wrap avg()/division results with round() before comparing to integral paths."],"tags":["hibernate","type-coercion","integer","double","fractional"],"backgroundTag":"fractional-to-integer-coercion","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}