quarkusio/quarkus · error · UnsupportedOperationException
It's not possible to compile H2 triggers when embedding the
Error message
It's not possible to compile H2 triggers when embedding the engine in GraalVM native images
What it means
Quarkus substitutes H2's SourceCompiler.isJavaxScriptSource with a stub that always throws UnsupportedOperationException when compiling a native image. H2's support for compiled (Java-source) triggers depends on the javax.script compiler, which cannot work in GraalVM native images because it generates and loads classes at runtime. This is an intentional hard failure to surface unsupported functionality at the point of use.
Source
Thrown at extensions/jdbc/jdbc-h2/runtime/src/main/java/io/quarkus/jdbc/h2/runtime/graalvm/DisableSourceCompiler.java:21
import java.lang.reflect.Method;
import javax.script.CompiledScript;
import javax.script.ScriptException;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
@Substitute
@TargetClass(className = "org.h2.util.SourceCompiler")
public final class DisableSourceCompiler {
private static final String ERR = "It's not possible to compile H2 triggers when embedding the engine in GraalVM native images";
//Delete it all
@Substitute
public static boolean isJavaxScriptSource(String source) {
throw new UnsupportedOperationException(ERR);
}
@Substitute
public CompiledScript getCompiledScript(String packageAndClassName) throws ScriptException {
throw new UnsupportedOperationException(ERR);
}
@Substitute
public Class<?> getClass(String packageAndClassName)
throws ClassNotFoundException {
throw new UnsupportedOperationException(ERR);
}
@Substitute
public void setSource(String className, String source) {
//no-op
}
View on GitHub (pinned to e1c734241f)
Solutions
- Replace compiled Java triggers with standard SQL triggers or database-side logic supported in native images.
- Move trigger creation out of native-mode startup/migrations, or gate Flyway/Liquibase locations per profile so native mode skips Java-trigger DDL.
- Run that workload in JVM mode instead of native image.
- Use an external Java component to implement the logic the trigger performed.
Example fix
// before CREATE TRIGGER t BEFORE INSERT ON t FOR EACH ROW AS $JAVA_SOURCE$ ... $ // compiled trigger // after CREATE TRIGGER t BEFORE INSERT ON t FOR EACH ROW SET NEW.updated = NOW(); // SQL-only trigger
Defensive patterns
Strategy: fallback
Validate before calling
if (ImageInfo.inImageRuntimeCode()) { /* avoid compiled-trigger DDL on H2 */ } Try / catch
try { stmt.execute(triggerDdl); } catch (UnsupportedOperationException e) { /* native mode: use SQL trigger instead */ } Prevention
- Never use H2 Java-source triggers in apps targeted for native compilation
- Add a native-mode test that runs your schema migrations
- Separate migration scripts for JVM and native profiles
- Prefer plain SQL logic in H2 test databases
When it happens
Trigger: Executing CREATE TRIGGER ... AS $JAVA_SOURCE$ (a compiled Java trigger) against an H2 database while the application runs as a GraalVM native image; H2 calls the substituted isJavaxScriptSource and hits the throw at DisableSourceCompiler.java:21.
Common situations: An app that works in JVM mode fails in native mode when a schema migration (Flyway/Liquibase) creates a Java-source trigger; test suites pass on JVM but a native CI job explodes at first DDL execution.
Related errors
- It's not possible to compile H2 triggers when embedding the
- Cannot parse version from output: ${stringOutput}
- Not Implemented in native mode
- Unable to create new instance for ${clazz}
- .pfa font files are not supported. Use TrueType fonts, i.e.
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/945d610b6e8e73f9.
Report an issue: GitHub.