{"record":{"id":"074b9f9722a0a500","repo":"pentaho/pentaho-kettle","slug":"jobexecutor-unexpectederror","errorCode":"JobExecutor.UnexpectedError","errorMessage":"JobExecutor.UnexpectedError","messagePattern":"JobExecutor\\.UnexpectedError","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/steps/jobexecutor/JobExecutor.java","lineNumber":173,"sourceCode":"        }\n      }\n\n      // Add next value AFTER job execution, in case we are grouping by field (see PDI-14958),\n      // and BEFORE checking size of a group, in case we are grouping by size (see PDI-14121).\n      data.groupBuffer.add( new RowMetaAndData( getInputRowMeta(), row ) ); // should we clone for safety?\n\n      // Grouping by size.\n      // If group buffer size exceeds specified limit, then execute job and flush group buffer.\n      if ( data.groupSize > 0 ) {\n        // Pass all input rows...\n        if ( data.groupBuffer.size() >= data.groupSize ) {\n          executeJob();\n        }\n      }\n\n      return true;\n    } catch ( Exception e ) {\n      throw new KettleException( BaseMessages.getString( PKG, \"JobExecutor.UnexpectedError\" ), e );\n    }\n  }\n\n  private void executeJob() throws KettleException {\n\n    // If we got 0 rows on input we don't really want to execute the job\n    //\n    if ( data.groupBuffer.isEmpty() ) {\n      return;\n    }\n\n    data.groupTimeStart = System.currentTimeMillis();\n\n    if ( first ) {\n      discardLogLines( data );\n    }\n\n    data.executorJob = createJob( meta.getRepository(), data.executorJobMeta, this );","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/steps/jobexecutor/JobExecutor.java#L155-L191","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// diagnosing\nlog layout shows:\nJobExecutor.UnexpectedError\n  Caused by: KettleException: Error loading job from repository : /jobs/load_orders\n// after\nFix the nested job definition or its path; this error itself has no code fix — it is a wrapper","handlingStrategy":"try-catch","validationCode":"// Validate the nested job is loadable before executing the parent transformation\nJobMeta jobMeta = new JobMeta(jobPath, repository, metaStore);\nif ( jobMeta == null || Const.isEmpty(jobMeta.getName()) ) {\n  throw new IllegalStateException(\"Nested job \" + jobPath + \" cannot be loaded\");\n}","typeGuard":"boolean hasRootCause(KettleException e, Class<? extends Exception> causeType) {\n  Throwable t = e;\n  while ( (t = t.getCause()) != null ) { if ( causeType.isInstance(t) ) return true; }\n  return false;\n}","tryCatchPattern":"try {\n  executeNestedJob();\n} catch ( KettleException e ) {\n  // UnexpectedError is a wrapper: always walk the cause chain for the real reason\n  Throwable root = e;\n  while ( root.getCause() != null ) { root = root.getCause(); }\n  logError(\"JobExecutor unexpected failure, root cause: \" + root.getMessage(), root);\n}","preventionTips":["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"],"tags":["pentaho-kettle","transformation","unexpected-error","wrapper-exception"],"backgroundTag":"internal-invariant-violation","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}