pentaho/pentaho-kettle · error · KettleException
JobExecutor.UnexpectedError
JobExecutor.UnexpectedError
Error message
JobExecutor.UnexpectedError
What it means
Generic catch-all wrapper in JobExecutor.processRow: any unexpected Exception thrown while executing the step (including failures inside executeJob() such as the nested job failing to start) is rethrown as a KettleException with the generic 'Unexpected error' message. The original cause is attached as the nested exception, so the real reason is in the cause chain.
Solutions
- Read the full stack trace and inspect the 'Caused by' entries to find the real root-cause exception
- Verify the nested job path/name configured in the step is valid and loadable in the current environment
- Run the nested job standalone to confirm it executes without errors
- Enable Kettle debug logging to capture the exact step where the failure originates
Example fix
// diagnosing log layout shows: JobExecutor.UnexpectedError Caused by: KettleException: Error loading job from repository : /jobs/load_orders // after Fix the nested job definition or its path; this error itself has no code fix — it is a wrapper
Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the nested job is loadable before executing the parent transformation
JobMeta jobMeta = new JobMeta(jobPath, repository, metaStore);
if ( jobMeta == null || Const.isEmpty(jobMeta.getName()) ) {
throw new IllegalStateException("Nested job " + jobPath + " cannot be loaded");
} Type guard
boolean hasRootCause(KettleException e, Class<? extends Exception> causeType) {
Throwable t = e;
while ( (t = t.getCause()) != null ) { if ( causeType.isInstance(t) ) return true; }
return false;
} Try / catch
try {
executeNestedJob();
} catch ( KettleException e ) {
// UnexpectedError is a wrapper: always walk the cause chain for the real reason
Throwable root = e;
while ( root.getCause() != null ) { root = root.getCause(); }
logError("JobExecutor unexpected failure, root cause: " + root.getMessage(), root);
} Prevention
- Always inspect the full cause chain in logs; the wrapper message 'Unexpected error' is never the real cause
- Run and test the nested job standalone before wiring it into a parent transformation
- Keep transformation and job files under version control so bad edits can be reverted
- Use distinct logging/exit statuses inside the nested job to surface its own failures
When it happens
Trigger: Any unhandled Exception escaping processRow other than the specific typed errors (e.g. GroupFieldNotFound) — most commonly an exception from executeJob(), job metadata loading, or result-row processing.
Common situations: Nested job fails to load from repository or file; null or missing job specification; errors during row grouping buffers; Kettle internal bugs; the true root cause is only visible in the 'cause' of this exception in the log.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- GetXMLData.Log.NoFiles (localized message)
- JobExecutor.Exception.GroupFieldNotFound
- The number of hops read
- The number of notes read
- TransLoadProgressDialog.Exception.ErrorLoadingTransformation
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/074b9f9722a0a500.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/jobexecutor/JobExecutor.java:173
}
}
// Add next value AFTER job execution, in case we are grouping by field (see PDI-14958),
// and BEFORE checking size of a group, in case we are grouping by size (see PDI-14121).
data.groupBuffer.add( new RowMetaAndData( getInputRowMeta(), row ) ); // should we clone for safety?
// Grouping by size.
// If group buffer size exceeds specified limit, then execute job and flush group buffer.
if ( data.groupSize > 0 ) {
// Pass all input rows...
if ( data.groupBuffer.size() >= data.groupSize ) {
executeJob();
}
}
return true;
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString( PKG, "JobExecutor.UnexpectedError" ), e );
}
}
private void executeJob() throws KettleException {
// If we got 0 rows on input we don't really want to execute the job
//
if ( data.groupBuffer.isEmpty() ) {
return;
}
data.groupTimeStart = System.currentTimeMillis();
if ( first ) {
discardLogLines( data );
}
data.executorJob = createJob( meta.getRepository(), data.executorJobMeta, this );View on GitHub (pinned to f3058517a1)