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

  1. Read the cause (and its cause) - the real failing attribute/type is named there, not in the outer message.
  2. Keep aggregate embeddable attributes to basic types or nested aggregates; add an AttributeConverter for exotic types so the visitor writes a basic value.
  3. 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

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


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/078d264aa45e9b9c. Report an issue: GitHub.