{"record":{"id":"6e4927abe8563f82","repo":"quarkusio/quarkus","slug":"it-s-not-possible-to-compile-h2-triggers-when-embe-6e4927","errorCode":null,"errorMessage":"It's not possible to compile H2 triggers when embedding the engine in GraalVM native images","messagePattern":"It's not possible to compile H2 triggers when embedding the engine in GraalVM native images","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"extensions/jdbc/jdbc-h2/runtime/src/main/java/io/quarkus/jdbc/h2/runtime/graalvm/NoCompiledTriggersSupport.java","lineNumber":14,"sourceCode":"package io.quarkus.jdbc.h2.runtime.graalvm;\n\nimport org.h2.engine.Database;\nimport org.h2.util.SourceCompiler;\n\nimport com.oracle.svm.core.annotate.Substitute;\nimport com.oracle.svm.core.annotate.TargetClass;\n\n@TargetClass(Database.class)\npublic final class NoCompiledTriggersSupport {\n\n    @Substitute\n    public SourceCompiler getCompiler() {\n        throw new UnsupportedOperationException(\n                \"It's not possible to compile H2 triggers when embedding the engine in GraalVM native images\");\n    }\n\n}\n","sourceCodeStart":1,"sourceCodeEnd":19,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/jdbc/jdbc-h2/runtime/src/main/java/io/quarkus/jdbc/h2/runtime/graalvm/NoCompiledTriggersSupport.java#L1-L19","documentation":"Quarkus substitutes H2's Database.getCompiler with a stub in NoCompiledTriggersSupport that always throws UnsupportedOperationException in native images. This is the top-level guard: any H2 code path requesting the SourceCompiler for compiled triggers fails immediately, because generating/loading trigger classes at runtime cannot work in a GraalVM native image.","triggerScenarios":"H2's engine calling Database.getCompiler() to obtain a compiler for a CREATE TRIGGER ... AS $JAVA_SOURCE$ statement executed in a native image; the @Substitute at NoCompiledTriggersSupport.java:14 throws unconditionally.","commonSituations":"Startup migrations (Flyway/Liquibase) defining Java-source triggers; JVM-mode dev environment working while the native production build fails on first DDL or trigger-related statement.","solutions":["Rewrite compiled triggers as plain SQL triggers.","Skip compiled-trigger DDL in native mode via profile-specific migration locations.","Use JVM mode for workloads requiring compiled H2 triggers.","Move trigger logic into application code (entity listeners, services)."],"exampleFix":"// before\n-- V2__java_trigger.sql\nCREATE TRIGGER t BEFORE INSERT ON logs FOR EACH ROW AS $JAVA_SOURCE$ ... $\n\n// after\n-- V2__sql_trigger.sql\nCREATE TRIGGER t BEFORE INSERT ON logs FOR EACH ROW SET NEW.created = CURRENT_TIMESTAMP;","handlingStrategy":"fallback","validationCode":"boolean avoidCompiledTriggers = ImageInfo.inImageRuntimeCode();","typeGuard":null,"tryCatchPattern":"try { db.runMigration(); } catch (UnsupportedOperationException e) { /* H2 compiled triggers not available in native image */ }","preventionTips":["CI: run at least one native-image test executing all migrations","Grep migrations for '$JAVA_SOURCE$' before enabling native builds","Keep dev/test DB behavior identical to native prod (SQL-only triggers)","Prefer PostgreSQL via Testcontainers when triggers are essential"],"tags":["graalvm","native-image","h2","unsupported-operation"],"backgroundTag":"unsupported-in-native-image","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}