pentaho/pentaho-kettle · error · RuntimeException
RulesData.Error.CompileDRL
RulesData.Error.CompileDRL
Error message
RulesData.Error.CompileDRL
What it means
In RulesExecutorData.initializeRules(), when no inline rule string is set, the step opens the configured rule file with new FileInputStream(ruleFilePath); if the file does not exist, the caught FileNotFoundException is rethrown as a RuntimeException carrying the (misleading) i18n message "RulesData.Error.CompileDRL". Despite the message, this specific throw at line 107 is a file-not-found problem, not a DRL compilation problem.
Solutions
- Verify the path in the Rules Executor step dialog and use an absolute path (or correct variables) — then check `new File(path).exists()` in the same environment where the transformation runs.
- If variables are used, confirm they resolve at runtime (log them via a 'Write to Log' step or getVariable in a UDJC).
- On clustered runs, make sure the DRL file exists at the same location on every slave node, or embed the rule inline (ruleString) instead of a file path.
- Confirm file read permissions for the user running the JVM/PDI.
Example fix
// before
stepMeta.setRuleFilePath("rules/my-rules.drl"); // relative, cwd-dependent
// after
stepMeta.setRuleFilePath("/opt/pdi/rules/my-rules.drl"); // absolute, or embed via setRuleString Defensive patterns
Strategy: validation
Validate before calling
// Before initializeRules(), verify the rule file is readable
String path = data.getRuleFilePath();
if (data.getRuleString() == null) {
java.io.File f = new java.io.File(path);
if (!f.isAbsolute()) throw new IllegalStateException("rule file path must be absolute or resolved: " + path);
if (!f.exists()) throw new IllegalStateException("rule file not found: " + path);
if (!f.canRead()) throw new IllegalStateException("rule file not readable: " + path);
} Try / catch
try {
data.initializeRules();
} catch (RuntimeException e) {
if (String.valueOf(e.getMessage()).contains("CompileDRL") && data.getRuleString() == null) {
throw new KettleStepException("Rule file not found: " + data.getRuleFilePath()
+ " — note the message says CompileDRL but this path is a FileNotFoundException", e);
}
throw e;
} Prevention
- Use absolute paths or resolve ${Internal.Transformation.Filename.Directory} variables
- Verify variables resolve at runtime (log them before the step)
- On clustered executions, ensure the DRL exists on every node, or embed the rule inline
- Check filesystem permissions for the user running the PDI JVM
When it happens
Trigger: Calling initializeRules() on a RulesExecutorData with ruleString == null and ruleFilePath pointing to a path that does not exist or is not readable at runtime — e.g. a relative path resolved against a different working directory, a file referenced on a local disk while the transformation runs on a cluster node, or a variable in the path left unexpanded.
Common situations: Using ${Internal.Transformation.Filename.Directory}-style variables that are empty when run outside the repository; agent/Spoon working directory differs from the one used when configuring the step; file was moved/deleted; path points to a cluster slave where the file is absent.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Error reading DBF file
- RulesData.Error.CompileDRL
- AccessInput.Log.RequiredFilesMissing
- Cannot open control file
- Cannot open data file
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/db5a0b514f849af6.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/drools/core/src/main/java/org/pentaho/di/trans/steps/rules/RulesExecutorData.java:107
public void initializeRules() {
// To ensure the plugin classloader use for dependency resolution
ClassLoader orig = Thread.currentThread().getContextClassLoader();
ClassLoader loader = getClass().getClassLoader();
Thread.currentThread().setContextClassLoader( loader );
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = kieServices.newKieFileSystem();
String internalFilePath = "src/main/resources/kettle.drl";
if ( ruleString != null ) {
kfs.write( internalFilePath, ruleString );
} else {
try {
FileInputStream fis = new FileInputStream( ruleFilePath );
kfs.write( internalFilePath, kieServices.getResources().newInputStreamResource( fis ) );
} catch ( FileNotFoundException e ) {
throw new RuntimeException( BaseMessages.getString( PKG, "RulesData.Error.CompileDRL" ) );
}
}
KieBuilder kieBuilder = kieServices.newKieBuilder( kfs ).buildAll();
Results results = kieBuilder.getResults();
if ( results.hasMessages( Message.Level.ERROR ) ) {
System.out.println( results.getMessages() );
throw new RuntimeException( BaseMessages.getString( PKG, "RulesData.Error.CompileDRL" ) );
}
KieContainer kieContainer = kieServices.newKieContainer( kieServices.getRepository().getDefaultReleaseId() );
kieBase = kieContainer.getKieBase();
// reset classloader back to original
Thread.currentThread().setContextClassLoader( orig );
}
public void initializeColumns( RowMetaInterface inputRowMeta ) {View on GitHub (pinned to f3058517a1)