hibernate/hibernate-orm · error · IllegalArgumentException

Malformed JSON. Expected array but got: " + event

Error message

Malformed JSON. Expected array but got: " + event

What it means

JsonHelper.deserializeArray expects the top-level element of a JSON column bound to a plural (array/collection) attribute to be an array. If the reader yields an object, scalar or boolean instead, it throws IllegalArgumentException('Malformed JSON. Expected array but got: <event>') - valid JSON, wrong shape for the collection mapping.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JsonHelper.java:259

			String string,
			WrapperOptions options) throws SQLException {
		if ( string == null ) {
			return null;
		}
		return deserializeArray( javaType, elementJdbcType, new StringJsonDocumentReader( string ), options );
	}

	public static <X> X deserializeArray(
			JavaType<X> javaType,
			JdbcType elementJdbcType,
			JsonDocumentReader reader,
			WrapperOptions options) throws SQLException {
		final JsonDocumentItemType event;
		if ( !reader.hasNext() || ( event = reader.next() ) == JsonDocumentItemType.NULL_VALUE ) {
			return null;
		}
		if ( event != JsonDocumentItemType.ARRAY_START ) {
			throw new IllegalArgumentException("Malformed JSON. Expected array but got: " + event);
		}

		final CustomArrayList arrayList = new CustomArrayList();
		final JavaType<?> elementJavaType = ((BasicPluralJavaType<?>) javaType).getElementJavaType();
		final Class<?> preferredJavaTypeClass = elementJdbcType.getPreferredJavaTypeClass( options );
		final JavaType<?> jdbcJavaType;
		if ( preferredJavaTypeClass == null || preferredJavaTypeClass == elementJavaType.getJavaTypeClass() ) {
			jdbcJavaType = elementJavaType;
		}
		else {
			jdbcJavaType = options.getTypeConfiguration().getJavaTypeRegistry().resolveDescriptor( preferredJavaTypeClass );
		}

		final JsonValueJDBCTypeAdapter adapter = JsonValueJDBCTypeAdapterFactory.getAdapter(reader,false);
		while(reader.hasNext()) {
			JsonDocumentItemType type = reader.next();
			switch ( type ) {
				case ARRAY_END:

View on GitHub (pinned to fad1729dce)

Solutions

  1. If the data is an object, map the attribute as an @Embedded aggregate instead of a collection.
  2. If the mapping is correct, migrate the stored data to a JSON array (e.g., jsonb: UPDATE t SET doc = jsonb_build_array(doc)).

Example fix

// before: column holds {"a":1} but attribute is a plural JSON type
@JdbcTypeCode(SqlTypes.JSON)
List<Item> items; // load -> Malformed JSON. Expected array but got: OBJECT_START

// after: align data with mapping
UPDATE t SET doc = jsonb_build_array(doc);
// or change mapping to @Embedded Item item;
Defensive patterns

Strategy: validation

Validate before calling

// Validate the top-level shape before loading a collection attribute (Jackson example)
static void assertTopLevelArray(String json) {
    com.fasterxml.jackson.databind.JsonNode n;
    try { n = new com.fasterxml.jackson.databind.ObjectMapper().readTree(json); }
    catch (Exception e) { throw new IllegalArgumentException("Invalid JSON", e); }
    if (!n.isArray()) {
        throw new IllegalArgumentException("Expected a JSON array for the collection mapping, got: " + n.getNodeType());
    }
}

Try / catch

try {
    return session.find(Product.class, id);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Malformed JSON. Expected array")) {
        // column holds an object/scalar where a collection is mapped: fix mapping or wrap data in []
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Reading a @JdbcTypeCode(SqlTypes.JSON) List<T>/T[] attribute whose column holds an object or scalar - mapping flipped between singular aggregate and collection, or another writer stored an object in the column.

Common situations: Refactoring an attribute from embeddable aggregate to List<embeddable> (or back) without data migration; consumers writing objects into a column the application reads as an array.

Understand the failure class

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/1b083cdded063b38. Report an issue: GitHub.