hibernate/hibernate-orm · error · QueryException

Can't emulate on error clause on MariaDB

Error message

Can't emulate on error clause on MariaDB

What it means

MariaDB reports json_value path errors as warning 4038 and returns null, so only NULL ON ERROR is emulatable. The MariaDB json_value renderer rejects every other ON ERROR behavior with this QueryException before SQL is generated.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/dialect/function/json/MariaDBJsonValueFunction.java:40

/**
 * MariaDB json_value function.
 */
public class MariaDBJsonValueFunction extends JsonValueFunction {

	public MariaDBJsonValueFunction(TypeConfiguration typeConfiguration) {
		super( typeConfiguration, true, false );
	}

	@Override
	protected void render(
			SqlAppender sqlAppender,
			JsonValueArguments arguments,
			ReturnableType<?> returnType,
			SqlAstTranslator<?> walker) {
		if ( arguments.errorBehavior() != null && arguments.errorBehavior() != JsonValueErrorBehavior.NULL ) {
			// MariaDB reports the error 4038 as warning and simply returns null
			throw new QueryException( "Can't emulate on error clause on MariaDB" );
		}
		if ( arguments.emptyBehavior() != null && arguments.emptyBehavior() != JsonValueEmptyBehavior.NULL ) {
			throw new QueryException( "Can't emulate on empty clause on MariaDB" );
		}
			final JdbcType jdbcType = arguments.returningType() == null
					? null
					: arguments.returningType().getJdbcMapping().getJdbcType();
			if ( jdbcType != null ) {
				switch ( jdbcType.getDefaultSqlTypeCode() ) {
					case BOOLEAN:
						sqlAppender.append( "case " );
						break;
					case BINARY:
					case VARBINARY:
					case LONG32VARBINARY:
						// We encode binary data as hex, so we have to decode here
						sqlAppender.append( "unhex(json_unquote(" );
						break;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove the ON ERROR clause: plain json_value(doc, path) already returns null on error on MariaDB.
  2. Use NULL ON ERROR explicitly if you want the behavior documented in the query.
  3. Implement the DEFAULT fallback with coalesce() around json_value.
  4. Handle the miss in application code after the query returns null.

Example fix

// before
select json_value(e.doc, '$.name' default 'n/a' on error) from Entity e

// after
select coalesce(json_value(e.doc, '$.name' null on error), 'n/a') from Entity e
Defensive patterns

Strategy: fallback

Validate before calling

boolean mariadb = session.getJdbcServices().getDialect() instanceof org.hibernate.dialect.MariaDBDialect;
if (mariadb && errorBehavior != null && errorBehavior != NULL_ON_ERROR) {
    // Plan: drop the clause and wrap with coalesce for the default value.
    hql = hql.replace(" default " + defaultExpr + " on error", "");
    hql = "select coalesce(" + hql.substring(7), ", " + defaultExpr + ")"; // adjust to your query shape
}

Try / catch

try {
    return session.createQuery(hql, String.class).getSingleResult();
} catch (org.hibernate.QueryException e) {
    if (e.getMessage() != null && e.getMessage().contains("on error clause on MariaDB")) {
        // Fallback: NULL ON ERROR plus coalesce for the default value.
        return session.createQuery(fallbackHql, String.class).getSingleResult();
    }
    throw e;
}

Prevention

When it happens

Trigger: An HQL json_value call on MariaDB uses ERROR ON ERROR or DEFAULT <expr> ON ERROR. The check errorBehavior() != null && != JsonValueErrorBehavior.NULL fires.

Common situations: Queries ported from Oracle, where DEFAULT ... ON ERROR is common. Code that wants a fallback value when the path misses.

Related errors


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