{"record":{"id":"7b26f6cfd97244a9","repo":"pentaho/pentaho-kettle","slug":"jobexecutormeta-exception-unabletoloadjob-7b26f6","errorCode":"JobExecutorMeta.Exception.UnableToLoadJob","errorMessage":"JobExecutorMeta.Exception.UnableToLoadJob","messagePattern":"JobExecutorMeta\\.Exception\\.UnableToLoadJob","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/steps/jobexecutor/JobExecutorMeta.java","lineNumber":748,"sourceCode":"\n      // Set the correct filename inside the XML.\n      //\n      executorJobMeta.setFilename( newFilename );\n\n      // exports always reside in the root directory, in case we want to turn\n      // this into a file repository...\n      //\n      executorJobMeta.setRepositoryDirectory( new RepositoryDirectory() );\n\n      // change it in the job entry\n      //\n      fileName = newFilename;\n\n      setSpecificationMethod( ObjectLocationSpecificationMethod.FILENAME );\n\n      return proposedNewFilename;\n    } catch ( Exception e ) {\n      throw new KettleException( BaseMessages.getString(\n        PKG, \"JobExecutorMeta.Exception.UnableToLoadJob\", fileName ), e );\n    }\n  }\n\n  @Override\n  public StepDataInterface getStepData() {\n    return new JobExecutorData();\n  }\n\n  @Override\n  public StepIOMetaInterface getStepIOMeta() {\n    StepIOMetaInterface ioMeta = super.getStepIOMeta( false );\n    if ( ioMeta == null ) {\n\n      ioMeta = new StepIOMeta( true, true, true, false, true, false );\n\n      ioMeta.addStream( new Stream( StreamType.TARGET, executionResultTargetStepMeta, BaseMessages.getString(\n        PKG, \"JobExecutorMeta.ResultStream.Description\" ), StreamIcon.TARGET, null ) );","sourceCodeStart":730,"sourceCodeEnd":766,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/steps/jobexecutor/JobExecutorMeta.java#L730-L766","documentation":"JobExecutorMeta.exportResources() throws this KettleException when it fails to load the sub-job referenced by the Job Executor step during transformation export. The wrapping catch re-throws any exception from resolving/loading the job specification (by filename, repository reference, or direct definition), including the fileName that could not be loaded as a message parameter. It signals the referenced job metadata could not be turned into a JobMeta object.","triggerScenarios":"Calling exportResources() (e.g. during job/transformation export via testExportResources) when the referenced job file does not exist at fileName, the repository JobObjectReference cannot be resolved, or the job XML/kjb is malformed and JobMeta.loadJob fails.","commonSituations":"Exporting a transformation that uses a Job Executor step after the sub-job file was moved/renamed; relative path resolution failing because the transformation is exported to a different directory; referencing a job stored in a repository that is not connected or has been deleted; copying transformations between environments where the referenced job path is environment-specific.","solutions":["Verify the job file at the path stored in the Job Executor step (fileName) exists and is readable before exporting.","Re-open the step settings and re-select the job so the specification method and filename/reference are re-resolved.","Use ${Internal.Transformation.Filename.Directory}-relative paths instead of absolute paths so exports remain portable.","If the job is repository-based, connect to the correct repository and confirm the job object still exists under the stored id_path.","Open the referenced .kjb in Spoon to confirm it parses (a corrupt/incompatible job file also triggers this)."],"exampleFix":"// before ( Spoon, absolute path )\nJobExecutorMeta meta = ...;\nmeta.setFileName( \"/home/dev/jobs/run_etl.kjb\" );\nString archive = meta.exportResources( transMeta, name, files, prop, rep, ms );\n\n// after ( portable relative path, existence pre-checked )\nString dir = transMeta.getVariable( \"Internal.Transformation.Filename.Directory\" );\nString jobPath = dir + \"/run_etl.kjb\";\nif ( !new File( jobPath ).exists() ) {\n  throw new IllegalStateException( \"Referenced job missing: \" + jobPath );\n}\nmeta.setSpecificationMethod( ObjectLocationSpecificationMethod.FILENAME );\nmeta.setFileName( jobPath );\nString archive = meta.exportResources( transMeta, name, files, prop, rep, ms );","handlingStrategy":"validation","validationCode":"JobExecutorMeta m = ...;\nString jobFile = m.getFileName();\nif ( ObjectLocationSpecificationMethod.FILENAME.equals( m.getSpecificationMethod() )\n     && ( jobFile == null || !new File( jobFile ).canRead() ) ) {\n  throw new IllegalStateException( \"Job Executor references unreadable job: \" + jobFile );\n}","typeGuard":"boolean hasResolvableJobSpec( JobExecutorMeta m ) {\n  return m.getSpecificationMethod() != null &&\n    ( ObjectLocationSpecificationMethod.FILENAME.equals( m.getSpecificationMethod() )\n        ? new File( m.getFileName() ).canRead()\n        : m.getJobObjectId() != null );\n}","tryCatchPattern":"try {\n  String archive = meta.exportResources( transMeta, name, files, props, rep, ms );\n} catch ( KettleException e ) {\n  if ( e.getMessage() != null && e.getMessage().contains( meta.getFileName() ) ) {\n    throw new IllegalStateException( \"Fix Job Executor reference to: \" + meta.getFileName(), e );\n  }\n  throw e;\n}","preventionTips":["Prefer repository-relative or Internal.*-variable paths over absolute file paths in Job Executor steps.","Pre-check referenced job files exist before running export/share operations.","Keep sub-jobs in the same VCS/project directory tree as the parent transformation.","Open each referenced sub-job in Spoon after refactors to confirm it still resolves."],"tags":["kettle","job-executor","export-resources","file-not-found"],"backgroundTag":"file-not-found","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"}