hibernate/hibernate-orm · error · IllegalArgumentException
XML starts sub-object for a non-aggregate type at index %d.
Error message
XML starts sub-object for a non-aggregate type at index %d. Selectable [%s] is of type [%s]
What it means
While parsing an XML aggregate into an embeddable, Hibernate met a nested start tag for a selectable whose JdbcType is not an AggregateJdbcType. The stored data contains a sub-object where the current mapping declares a basic scalar, so element-wise parsing cannot proceed.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/XmlHelper.java:544
final int end = fromArrayString(
string,
returnEmbeddable,
options,
i,
arrayList,
elementType.getMappedJavaType(),
elementType.getJdbcJavaType(),
elementType.getJdbcType()
);
values[selectableIndex] = selectable.getJdbcMapping().getJdbcJavaType().wrap( arrayList, options );
// The end is the start angle bracket for the end tag
assert string.charAt( end ) == '<';
assert string.charAt( end + 1 ) == '/';
assert string.regionMatches( end + 2, tagName, 0, tagName.length() );
i = end;
}
else {
throw new IllegalArgumentException(
String.format(
"XML starts sub-object for a non-aggregate type at index %d. Selectable [%s] is of type [%s]",
i,
selectable.getSelectableName(),
jdbcType.getClass().getName()
)
);
}
}
// consume the whole closing tag
i += tagName.length() + 2;
tagNameStart = -1;
contentStart = -1;
tagName = null;
}
break;
case '>':
if ( tagName == null ) {View on GitHub (pinned to fad1729dce)
Solutions
- Align the mapping with the stored shape: re-introduce the nested embeddable the data still has.
- Or migrate the column data to the new flat shape before deploying the new mapping.
- Version the aggregate layout and migrate rows on every layout change.
Example fix
// before: mapping declares a basic field, data has <address><city>..</city></address>
String city;
// after: mapping matches the stored nested object
@Embeddable
static class Address { String city; }
Address address; Defensive patterns
Strategy: validation
Validate before calling
// before deploying a refactored embeddable, compare stored tags with the mapping
Set<String> storedTags = extractChildTags(jdbc, "select xml_col from t");
Set<String> mappedTags = expectedTagsFor(Details.class); // field/@Column names
if (!mappedTags.containsAll(storedTags) || !storedTags.containsAll(mappedTags)) {
throw new IllegalStateException("XML aggregate layout drift: "
+ symmetricDifference(storedTags, mappedTags));
} Try / catch
try {
return session.find(Person.class, id);
} catch (IllegalArgumentException ex) {
if (ex.getMessage() != null && ex.getMessage().contains("XML starts sub-object")) {
// row layout is newer/older than the deployed mapping
quarantine(id, ex.getMessage());
return null;
}
throw ex;
} Prevention
- Treat aggregate layout changes as schema changes: write a data migration for every refactor.
- Compare stored element tags against the embeddable's field names in a pre-deploy check.
- Never share one XML column between mappings with different nesting.
When it happens
Trigger: Loading an entity after the embeddable was refactored: a nested embeddable flattened to a basic field (or a field moved between nesting levels) while stored rows still contain the nested tags. Also data written by a different mapping where the field was an aggregate.
Common situations: Schema/refactor drift between application versions; sharing one XML column between two mappings; restoring old backups into a new schema.
Related errors
- Could not find selectable [%s] in embeddable type [%s] for X
- Could not find selectable [%s] in embeddable type [%s] for J
- Illegal XML content:
- XML not properly formatted:
- XML not properly formed:
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/dd9905636609e4d6.
Report an issue: GitHub.