{"record":{"id":"dd9905636609e4d6","repo":"hibernate/hibernate-orm","slug":"xml-starts-sub-object-for-a-non-aggregate-type-at","errorCode":null,"errorMessage":"XML starts sub-object for a non-aggregate type at index %d. Selectable [%s] is of type [%s]","messagePattern":"XML starts sub-object for a non-aggregate type at index (.+?)\\. Selectable \\[(.+?)\\] is of type \\[(.+?)\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/XmlHelper.java","lineNumber":544,"sourceCode":"\t\t\t\t\t\t\t\tfinal int end = fromArrayString(\n\t\t\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\t\t\treturnEmbeddable,\n\t\t\t\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\t\t\t\ti,\n\t\t\t\t\t\t\t\t\t\tarrayList,\n\t\t\t\t\t\t\t\t\t\telementType.getMappedJavaType(),\n\t\t\t\t\t\t\t\t\t\telementType.getJdbcJavaType(),\n\t\t\t\t\t\t\t\t\t\telementType.getJdbcType()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tvalues[selectableIndex] = selectable.getJdbcMapping().getJdbcJavaType().wrap( arrayList, options );\n\t\t\t\t\t\t\t\t// The end is the start angle bracket for the end tag\n\t\t\t\t\t\t\t\tassert string.charAt( end ) == '<';\n\t\t\t\t\t\t\t\tassert string.charAt( end + 1 ) == '/';\n\t\t\t\t\t\t\t\tassert string.regionMatches( end + 2, tagName, 0, tagName.length() );\n\t\t\t\t\t\t\t\ti = end;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\t\t\t\t\t\"XML starts sub-object for a non-aggregate type at index %d. Selectable [%s] is of type [%s]\",\n\t\t\t\t\t\t\t\t\t\t\t\ti,\n\t\t\t\t\t\t\t\t\t\t\t\tselectable.getSelectableName(),\n\t\t\t\t\t\t\t\t\t\t\t\tjdbcType.getClass().getName()\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// consume the whole closing tag\n\t\t\t\t\t\ti += tagName.length() + 2;\n\t\t\t\t\t\ttagNameStart = -1;\n\t\t\t\t\t\tcontentStart = -1;\n\t\t\t\t\t\ttagName = null;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '>':\n\t\t\t\t\tif ( tagName == null ) {","sourceCodeStart":526,"sourceCodeEnd":562,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/XmlHelper.java#L526-L562","documentation":"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.","triggerScenarios":"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.","commonSituations":"Schema/refactor drift between application versions; sharing one XML column between two mappings; restoring old backups into a new schema.","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."],"exampleFix":"// before: mapping declares a basic field, data has <address><city>..</city></address>\nString city;\n// after: mapping matches the stored nested object\n@Embeddable\nstatic class Address { String city; }\nAddress address;","handlingStrategy":"validation","validationCode":"// before deploying a refactored embeddable, compare stored tags with the mapping\nSet<String> storedTags = extractChildTags(jdbc, \"select xml_col from t\");\nSet<String> mappedTags = expectedTagsFor(Details.class); // field/@Column names\nif (!mappedTags.containsAll(storedTags) || !storedTags.containsAll(mappedTags)) {\n    throw new IllegalStateException(\"XML aggregate layout drift: \" \n        + symmetricDifference(storedTags, mappedTags));\n}","typeGuard":null,"tryCatchPattern":"try {\n    return session.find(Person.class, id);\n} catch (IllegalArgumentException ex) {\n    if (ex.getMessage() != null && ex.getMessage().contains(\"XML starts sub-object\")) {\n        // row layout is newer/older than the deployed mapping\n        quarantine(id, ex.getMessage());\n        return null;\n    }\n    throw ex;\n}","preventionTips":["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."],"tags":["hibernate","xml","xml-aggregate","schema-drift","embeddable"],"backgroundTag":"xml-data-mapping-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}