hibernate/hibernate-orm · error · IllegalArgumentException
Illegal XML content:
Error message
Illegal XML content:
What it means
XmlHelper.unescape understands only the five named XML entities (< & ' > "). When Hibernate reads an XML-mapped aggregate column, any other ampersand sequence in the text content fails entity matching and throws IllegalArgumentException with the offending content. This includes numeric character references, HTML-only entities, and bare '&' characters.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/XmlHelper.java:116
case 'g':
if ( string.charAt( i + 2 ) == 't' && string.charAt( i + 3 ) == ';' ) {
sb.append( '>' );
i += 3;
}
break OUTER;
case 'q':
if ( i + 5 < end
&& string.charAt( i + 2 ) == 'u'
&& string.charAt( i + 3 ) == 'o'
&& string.charAt( i + 4 ) == 't'
&& string.charAt( i + 5 ) == ';' ) {
sb.append( '"' );
i += 5;
}
break OUTER;
}
}
throw new IllegalArgumentException( "Illegal XML content: " + string.substring( start, end ) );
default:
sb.append( c );
break;
}
}
return sb.toString();
}
private static Object fromString(
EmbeddableMappingType embeddableMappingType,
String string,
boolean returnEmbeddable,
WrapperOptions options,
int selectableIndex,
int start,
int end) throws SQLException {
final JdbcMapping jdbcMapping = embeddableMappingType.getJdbcValueSelectable( selectableIndex )
.getJdbcMapping();View on GitHub (pinned to fad1729dce)
Solutions
- Repair the stored data: replace unsupported entities with the literal character and escape stray '&' as '&'.
- Write XML aggregate values only through Hibernate so escaping stays consistent.
- Add an ingest-time sanitizer if external writers must touch the column.
- Audit the column for suspicious '&' rows before switching reads to Hibernate.
Example fix
-- PostgreSQL audit + fix -- before: content holds ' ' or 'A' UPDATE t SET doc = REPLACE(doc, ' ', ' ') WHERE doc LIKE '% %'; SELECT id FROM t WHERE doc ~ '&(?!amp;|lt;|gt;|apos;|quot;)' AND doc LIKE '%<e>%';
Defensive patterns
Strategy: try-catch
Validate before calling
static boolean hasOnlySupportedEntities(String content) {
return content == null || !content.matches("(?s).*&(?!(amp|lt|gt|apos|quot);).*");
} Try / catch
try {
return session.find(Person.class, id); // materializes the XML aggregate
} catch (IllegalArgumentException ex) {
if (ex.getMessage() != null && ex.getMessage().startsWith("Illegal XML content")) {
quarantine(id, ex.getMessage()); // log PK + offending content, schedule repair
return null;
}
throw ex;
} Prevention
- Let Hibernate be the only writer of XML aggregate columns.
- Sanitize inbound XML data (escape stray '&' as '&', resolve numeric/HTML entities) at ingest.
- Audit columns for unsupported entities before enabling Hibernate reads.
When it happens
Trigger: Reading an XML aggregate (XmlJdbcType / SqlTypes.SQLXML mapping) whose stored text contains an ampersand sequence outside the five supported entities, e.g. 'A', ' ', 'A', or an unescaped '&' followed by a character other than l/a/g/q; also an entity truncated at the end of the content region.
Common situations: Rows written by another application, ETL job, or script that used broader XML/HTML escaping; hand-edited column values; data migrated from standard XML documents into a Hibernate XML aggregate column.
Related errors
- XML not properly formatted:
- XML not properly formed:
- XML starts sub-object for a non-aggregate type at index %d.
- Support for attribute mapping type not yet implemented:
- Could not find selectable [%s] in embeddable type [%s] for X
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/4d3d7ca6702da2a4.
Report an issue: GitHub.