hibernate/hibernate-orm · error · IllegalArgumentException
Could not deserialize string to java type: {}
Error message
Could not deserialize string to java type: {} What it means
JacksonXmlFormatMapper is the FormatMapper Hibernate uses for @JdbcTypeCode(SqlTypes.SQLXML) attributes via jackson-dataformat-xml. This IllegalArgumentException (JacksonXmlFormatMapper.java:163) wraps a JsonProcessingException raised when the stored XML cannot be parsed into the attribute's Java type, including the Map/array paths that depend on the mapper's legacyFormat flag. The stored XML layout for collections and maps changed between Hibernate versions, controlled by hibernate.type.xml_format_mapper.legacy_format.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonXmlFormatMapper.java:163
);
return javaType.wrap( collectionWrapper.value, wrapperOptions );
}
else if ( javaType.getJavaTypeClass().isArray() ) {
final CollectionWrapper<?> collectionWrapper = objectMapper.readValue(
charSequence.toString(),
objectMapper.constructType( new ParameterizedTypeImpl( CollectionWrapper.class,
new Type[] {javaType.getJavaTypeClass().getComponentType()}, null ) )
);
return javaType.wrap( collectionWrapper.value, wrapperOptions );
}
}
return objectMapper.readValue(
charSequence.toString(),
objectMapper.constructType( javaType.getJavaType() )
);
}
catch (JsonProcessingException e) {
throw new IllegalArgumentException( "Could not deserialize string to java type: " + javaType, e );
}
}
@Override
public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
if ( javaType.getJavaType() == String.class || javaType.getJavaType() == Object.class ) {
return (String) value;
}
if ( !legacyFormat ) {
if ( Map.class.isAssignableFrom( javaType.getJavaTypeClass() ) ) {
final Type keyType;
final Type elementType;
if ( javaType.getJavaType() instanceof ParameterizedType parameterizedType ) {
keyType = parameterizedType.getActualTypeArguments()[0];
elementType = parameterizedType.getActualTypeArguments()[1];
}
else {
keyType = Object.class;View on GitHub (pinned to fad1729dce)
Solutions
- If the data was written by an older Hibernate, set hibernate.type.xml_format_mapper.legacy_format=true so the mapper reads the legacy wrapper layout.
- Compare a failing column value against the attribute type and fix the data or the mapping so element names/shape match.
- Make the target type Jackson-XML friendly: default constructor, @JacksonXmlProperty/@JacksonXmlRootElement names matching the stored XML.
- Migrate stored XML with a one-off script when the attribute type changes.
- Supply a customized XmlMapper through JacksonXmlFormatMapper(ObjectMapper, legacyFormat) via the hibernate.type.xml_format_mapper setting if you need bespoke handling.
Example fix
// before - rows written by old Hibernate fail to read after upgrade
<persistence ...>
<properties>
<property name="hibernate.type.xml_format_mapper" value="jackson-xml"/>
</properties>
// after - opt into the legacy XML layout for pre-upgrade data
<property name="hibernate.type.xml_format_mapper.legacy_format" value="true"/> Defensive patterns
Strategy: try-catch
Validate before calling
// After a Hibernate upgrade, sample existing rows and check they parse
XmlMapper xml = XmlMapper.builder().findAndAddModules().build();
for ( String storedXml : sampleColumnValues() ) {
xml.readValue( storedXml, MyXmlType.class ); // throws early with a clear location
} Try / catch
try {
return session.find( Doc.class, id );
} catch ( IllegalArgumentException e ) {
if ( e.getCause() instanceof com.fasterxml.jackson.core.JsonProcessingException jpe ) {
// stored XML does not match attribute type / format version - check jpe.getLocation()
} else throw e;
} Prevention
- Set hibernate.type.xml_format_mapper.legacy_format=true immediately after upgrading if you have pre-upgrade XML data, then migrate at leisure.
- Pin the XML format: test stored-XML layout in golden-file tests so format changes surface in CI.
- Migrate column data in the same release that changes the attribute type.
- Validate external XML against the XmlMapper before it enters the column.
When it happens
Trigger: Loading an entity with a SqlTypes.SQLXML attribute whose column XML is malformed or does not match the attribute type; reading XML written by an older Hibernate version (legacy <Collection><e>... wrapper layout) while running with the new non-legacy default (legacyFormat=false in JacksonXmlFormatMapper.java:58-61); mapping a POJO whose fields do not match the XML element names; attribute types Jackson-XML cannot construct (no default constructor).
Common situations: Upgrading Hibernate across the version that introduced the new XML format and reading pre-existing rows; changing the attribute type (List to Map or vice versa) without migrating stored XML; external systems writing the XML column with a different layout.
Related errors
- Could not serialize object of java type: {}
- Could not deserialize string to java type: {}
- Could not deserialize string to java type: {}
- Could not deserialize string to java type: {}
- Could not serialize object of java type: {}
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/eb4ad48ac862835d.
Report an issue: GitHub.