hibernate/hibernate-orm · error · IllegalArgumentException
Expected array or collection value, but got:
Error message
Expected array or collection value, but got:
What it means
JsonGeneratingVisitor.visitArray accepts only Java arrays and java.util.Collection values when serializing an aggregate array element. If the runtime value is neither - a singular object, a wrapper, or an Iterator - it throws IllegalArgumentException naming the actual class.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/spi/JsonGeneratingVisitor.java:97
visit( embeddableMappingType, Array.get( values, j ), options, writer );
}
catch (IOException e) {
throw new IllegalArgumentException( "Could not serialize array element", e );
}
}
}
else if ( values instanceof Collection<?> collection ) {
for ( final var item : collection ) {
try {
visit( embeddableMappingType, item, options, writer );
}
catch (IOException e) {
throw new IllegalArgumentException( "Could not serialize array element", e );
}
}
}
else {
throw new IllegalArgumentException(
"Expected array or collection value, but got: " + values.getClass().getName()
);
}
}
private void visitBasicPluralValues(
JavaType<?> elementJavaType,
JdbcType elementJdbcType,
Object values,
WrapperOptions options,
JsonDocumentWriter writer) {
if ( values.getClass().isArray() ) {
final var length = Array.getLength( values );
for ( int j = 0; j < length; j++ ) {
final var item = Array.get( values, j );
if ( item == null ) {
writer.nullValue();
}View on GitHub (pinned to fad1729dce)
Solutions
- Make the custom JavaType/converter return an actual array or Collection for aggregate array values.
- Fix the attribute mapping so the declared element type matches the runtime value type.
- If the property is genuinely singular, map it as a plain aggregate (not an array aggregate).
Example fix
// before: custom plural JavaType returns a scalar
public Object wrap(Object value, WrapperOptions o) {
return ((Ids) value).first(); // -> Expected array or collection value
}
// after: return the plural form
public Object wrap(Object value, WrapperOptions o) {
return ((Ids) value).toList(); // List/Array is accepted
} Defensive patterns
Strategy: type-guard
Validate before calling
static boolean isPluralValue(Object value) {
return value == null || value instanceof Collection<?> || value.getClass().isArray();
} Type guard
static boolean canBindAsAggregateArray(Object value) {
return value == null || value instanceof Object[]
|| value instanceof Collection<?> || value.getClass().isArray();
} Try / catch
try {
session.persist(order);
} catch (IllegalArgumentException ex) {
if (ex.getMessage() != null && ex.getMessage().startsWith("Expected array or collection value")) {
throw new IllegalStateException(
"Aggregate array attribute holds a non-plural value; fix the JavaType/converter", ex);
}
throw ex;
} Prevention
- Make custom plural JavaTypes and converters always return arrays or Collections for aggregate array values.
- Assert the runtime value type matches the declared aggregate element type in unit tests.
- Do not map singular properties through array aggregate types.
When it happens
Trigger: The JavaType of an array-typed aggregate element hands a non-plural value to the serializer: a custom BasicPluralJavaType or JavaType whose wrap/unwrap returns a scalar, an AttributeConverter that strips the collection, or an element mapping whose declared type does not match the stored value type.
Common situations: Custom plural JavaTypes for array columns; converters applied to aggregate array attributes; mapping an attribute as an array aggregate while the domain property is singular.
Related errors
- Could not serialize array element
- Could not instantiate named strategy class [%s]
- Could not find a FormatMapper for the JSON format, which is
- Array element type error
- Can't emulate on error clause on CockroachDB
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/58152752a40b6ee1.
Report an issue: GitHub.