{"record":{"id":"a2c44f80e57c8ff5","repo":"hibernate/hibernate-orm","slug":"can-t-emulate-on-error-clause-on-mariadb","errorCode":null,"errorMessage":"Can't emulate on error clause on MariaDB","messagePattern":"Can't emulate on error clause on MariaDB","errorType":"exception","errorClass":"QueryException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/json/MariaDBJsonValueFunction.java","lineNumber":40,"sourceCode":"\n/**\n * MariaDB json_value function.\n */\npublic class MariaDBJsonValueFunction extends JsonValueFunction {\n\n\tpublic MariaDBJsonValueFunction(TypeConfiguration typeConfiguration) {\n\t\tsuper( typeConfiguration, true, false );\n\t}\n\n\t@Override\n\tprotected void render(\n\t\t\tSqlAppender sqlAppender,\n\t\t\tJsonValueArguments arguments,\n\t\t\tReturnableType<?> returnType,\n\t\t\tSqlAstTranslator<?> walker) {\n\t\tif ( arguments.errorBehavior() != null && arguments.errorBehavior() != JsonValueErrorBehavior.NULL ) {\n\t\t\t// MariaDB reports the error 4038 as warning and simply returns null\n\t\t\tthrow new QueryException( \"Can't emulate on error clause on MariaDB\" );\n\t\t}\n\t\tif ( arguments.emptyBehavior() != null && arguments.emptyBehavior() != JsonValueEmptyBehavior.NULL ) {\n\t\t\tthrow new QueryException( \"Can't emulate on empty clause on MariaDB\" );\n\t\t}\n\t\t\tfinal JdbcType jdbcType = arguments.returningType() == null\n\t\t\t\t\t? null\n\t\t\t\t\t: arguments.returningType().getJdbcMapping().getJdbcType();\n\t\t\tif ( jdbcType != null ) {\n\t\t\t\tswitch ( jdbcType.getDefaultSqlTypeCode() ) {\n\t\t\t\t\tcase BOOLEAN:\n\t\t\t\t\t\tsqlAppender.append( \"case \" );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BINARY:\n\t\t\t\t\tcase VARBINARY:\n\t\t\t\t\tcase LONG32VARBINARY:\n\t\t\t\t\t\t// We encode binary data as hex, so we have to decode here\n\t\t\t\t\t\tsqlAppender.append( \"unhex(json_unquote(\" );\n\t\t\t\t\t\tbreak;","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/json/MariaDBJsonValueFunction.java#L22-L58","documentation":"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.","triggerScenarios":"An HQL json_value call on MariaDB uses ERROR ON ERROR or DEFAULT <expr> ON ERROR. The check errorBehavior() != null && != JsonValueErrorBehavior.NULL fires.","commonSituations":"Queries ported from Oracle, where DEFAULT ... ON ERROR is common. Code that wants a fallback value when the path misses.","solutions":["Remove the ON ERROR clause: plain json_value(doc, path) already returns null on error on MariaDB.","Use NULL ON ERROR explicitly if you want the behavior documented in the query.","Implement the DEFAULT fallback with coalesce() around json_value.","Handle the miss in application code after the query returns null."],"exampleFix":"// before\nselect json_value(e.doc, '$.name' default 'n/a' on error) from Entity e\n\n// after\nselect coalesce(json_value(e.doc, '$.name' null on error), 'n/a') from Entity e","handlingStrategy":"fallback","validationCode":"boolean mariadb = session.getJdbcServices().getDialect() instanceof org.hibernate.dialect.MariaDBDialect;\nif (mariadb && errorBehavior != null && errorBehavior != NULL_ON_ERROR) {\n    // Plan: drop the clause and wrap with coalesce for the default value.\n    hql = hql.replace(\" default \" + defaultExpr + \" on error\", \"\");\n    hql = \"select coalesce(\" + hql.substring(7), \", \" + defaultExpr + \")\"; // adjust to your query shape\n}","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql, String.class).getSingleResult();\n} catch (org.hibernate.QueryException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"on error clause on MariaDB\")) {\n        // Fallback: NULL ON ERROR plus coalesce for the default value.\n        return session.createQuery(fallbackHql, String.class).getSingleResult();\n    }\n    throw e;\n}","preventionTips":["Do not use DEFAULT ... ON ERROR in shared HQL; use coalesce() around json_value.","Remember MariaDB always converts json_value errors to null.","Keep dialect-specific clause usage behind a dialect check."],"tags":["hibernate","mariadb","json","json-value","on-error-clause","dialect-emulation"],"backgroundTag":"json-on-error-clause-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}