hibernate/hibernate-orm · error · IllegalArgumentException

Illegal XML for array:

Error message

Illegal XML for array: 

What it means

XmlHelper.arrayFromString handles the read path for XML array attributes. It requires the column value to be <Collection> ... </Collection>, or <Collection/> for an empty array. Any other content throws IllegalArgumentException 'Illegal XML for array'.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/XmlHelper.java:324

			return (X) instantiate( embeddableMappingType, attributeValues );
		}
		//noinspection unchecked
		return (X) array;
	}

	public static <X> X arrayFromString(
			JavaType<X> javaType,
			XmlArrayJdbcType xmlArrayJdbcType,
			String string,
			WrapperOptions options) throws SQLException {
		if ( string == null ) {
			return null;
		}
		else if ( EMPTY_COLLECTION_TAG.equals( string ) ) {
			return javaType.wrap( Collections.emptyList(), options );
		}
		else if ( !string.startsWith( COLLECTION_START_TAG ) || !string.endsWith( COLLECTION_END_TAG ) ) {
			throw new IllegalArgumentException( "Illegal XML for array: " + string );
		}
		final JavaType<?> elementJavaType = ((BasicPluralJavaType<?>) javaType).getElementJavaType();
		final Class<?> preferredJavaTypeClass = xmlArrayJdbcType.getElementJdbcType().getPreferredJavaTypeClass( options );
		final JavaType<?> jdbcJavaType;
		if ( preferredJavaTypeClass == null || preferredJavaTypeClass == elementJavaType.getJavaTypeClass() ) {
			jdbcJavaType = elementJavaType;
		}
		else {
			jdbcJavaType = options.getTypeConfiguration().getJavaTypeRegistry().resolveDescriptor( preferredJavaTypeClass );
		}
		final ArrayList<Object> arrayList = new ArrayList<>();
		final int end = fromArrayString(
				string,
				true,
				options,
				COLLECTION_START_TAG.length(),
				arrayList,
				elementJavaType,

View on GitHub (pinned to fad1729dce)

Solutions

  1. Rewrite stored array values into <Collection>...</Collection> form (empty array exactly '<Collection/>').
  2. Write array values through Hibernate so the wrapper is always emitted.
  3. Check the attribute actually maps to XmlArrayJdbcType and the element type matches the stored elements.
Defensive patterns

Strategy: validation

Validate before calling

static boolean isHibernateAggregateArrayXml(String s) {
    return s == null || "<Collection/>".equals(s)
        || (s.startsWith("<Collection>") && s.endsWith("</Collection>"));
}

Try / catch

try {
    return session.find(Person.class, id);
} catch (IllegalArgumentException ex) {
    if (ex.getMessage() != null && ex.getMessage().startsWith("Illegal XML for array")) {
        quarantine(id, ex.getMessage());
        return null;
    }
    throw ex;
}

Prevention

When it happens

Trigger: Reading an attribute mapped with XmlArrayJdbcType (e.g. @Array / basic-array mapping on an XML column) whose stored value is not wrapped in the <Collection> tags: bare values, a different root element, or a plain empty string instead of <Collection/>.

Common situations: Array data written by an external tool or earlier Hibernate version; switching a column between scalar and array aggregate mappings; empty-string defaults on NOT NULL columns.

Related errors


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