hibernate/hibernate-orm · error · RuntimeException
Failed to serialize JSON mapping
Error message
Failed to serialize JSON mapping
What it means
JsonJdbcType.toString() serializes an aggregate (JSON)-mapped embeddable through JsonGeneratingVisitor; any IOException from the writer is wrapped in RuntimeException('Failed to serialize JSON mapping'). Because the writer is string-based, real I/O failure is unlikely - the wrapped cause usually hides a deeper serialization problem such as an attribute type the visitor cannot render. Always inspect the cause chain.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JsonJdbcType.java:122
}
@Override
public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options)
throws SQLException {
assert embeddableMappingType != null;
return JsonHelper.deserialize( embeddableMappingType,
new StringJsonDocumentReader( (String) rawJdbcValue ), false, options );
}
protected <X> String toString(X value, JavaType<X> javaType, WrapperOptions options) {
if ( embeddableMappingType != null ) {
try {
final var writer = new StringJsonDocumentWriter();
JsonGeneratingVisitor.INSTANCE.visit( embeddableMappingType, value, options, writer );
return writer.getJson();
}
catch (IOException e) {
throw new RuntimeException("Failed to serialize JSON mapping", e );
}
}
return options.getJsonFormatMapper().toString( value, javaType, options );
}
@Override
public <X> ValueBinder<X> getBinder(JavaType<X> javaType) {
return new BasicBinder<>( javaType, this ) {
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
st.setString( index, JsonJdbcType.this.toString( value, getJavaType(), options ) );
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setString( name, JsonJdbcType.this.toString( value, getJavaType(), options ) );View on GitHub (pinned to fad1729dce)
Solutions
- Read the cause (and its cause) - the real failing attribute/type is named there, not in the outer message.
- Keep aggregate embeddable attributes to basic types or nested aggregates; add an AttributeConverter for exotic types so the visitor writes a basic value.
- For complex values, map that attribute itself with a custom JsonFormatMapper-friendly type instead of relying on the visitor.
Example fix
// before: exotic attribute inside the JSON embeddable breaks the visitor
@Embeddable public class Config {
UUID tenantId; // renders fine
MyCustomType custom; // visitor cannot serialize -> RuntimeException on flush
}
// after: convert the exotic attribute to a supported basic value
@Embeddable public class Config {
UUID tenantId;
@Convert(converter = MyCustomTypeToStringConverter.class)
String custom;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Exercise serialization at startup so failures surface early
sessionFactory.inTransaction(s -> {
Product p = new Product();
p.setAttrs(defaultAttrs);
s.persist(p); // flush runs the JSON visitor now, not at 3am
s.remove(p);
}); Try / catch
try {
session.persist(entity);
session.flush();
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().equals("Failed to serialize JSON mapping")) {
Throwable cause = e.getCause(); // the real attribute/type failure is here
// log cause, fix or convert the offending embeddable attribute
} else {
throw e;
}
} Prevention
- Keep aggregate embeddables to basic types and nested aggregates; convert exotic types with @Convert
- Persist-and-flush a sample of every aggregate mapping in a startup/CI check
- Always unwrap the cause chain of this wrapper before debugging
When it happens
Trigger: Flushing or querying an entity with a json aggregate embeddable whose attribute values cannot be rendered by the visitor (exotic Java types without a usable JdbcLiteralFormatter/JdbcType), or string-conversion paths (e.g., literal rendering) hitting the same visitor.
Common situations: Custom or rarely used attribute types inside an @Embeddable mapped with @JdbcTypeCode(SqlTypes.JSON)/struct; mappings that work for normal columns but were never exercised through the JSON aggregate path; format-mapper configuration changes.
Related errors
- Could not find selectable [%s] in embeddable type [%s] for J
- Can't parse JSON object for selectable [%s] which is not of
- Support for model part type not yet implemented:
- unexpected JSON array type
- Unsupported JdbcType nested in JSON: {}
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/078d264aa45e9b9c.
Report an issue: GitHub.