pentaho/pentaho-kettle · error · KettleException
JobJobError.Recursive
Error message
JobJobError.Recursive
What it means
verifyRecursiveExecution() prevents a job entry from launching the same job it is already part of (infinite recursion). When the sub-job was loaded from a file and its filename equals the parent job's filename, a KettleException with localized message 'JobJobError.Recursive' (containing the filename) is thrown from the JobEntryJob constructor path.
Solutions
- Point the Job entry's filename to a different sub-job .kjb file
- Fix the variable so it does not resolve to the parent job's own path
- If recursion is intended, restructure with distinct jobs or use a different execution mechanism
- Check for path aliases (symlinks, VFS mounts) that make paths compare equal
Example fix
// before
// Filename: ${Internal.Job.Filename} (points at the job itself)
// after
// Filename: ${Internal.Job.Filename.Directory}/child_job.kjb Defensive patterns
Strategy: validation
Validate before calling
String parentFile = parentJobMeta.getFilename();
String subFile = environmentSubstitute(jobEntry.getFilename());
if (parentFile != null && parentFile.equals(subFile)) {
throw new IllegalArgumentException("Job entry references its own job file: " + subFile);
} Try / catch
try {
jobEntry.execute(result, nr);
} catch (KettleException e) {
if (e.getMessage().contains("recursive") || e.getMessage().contains("Recursive")) {
// fix the entry configuration; retrying cannot succeed
}
throw e;
} Prevention
- Never point a Job entry at the parent job's own .kjb file
- Be careful with ${Internal.Job.Filename} variables in sub-job fields
- Check for symlinks/path aliases that make two paths compare equal
- Restructure intentionally recursive workflows into distinct, parameterized jobs
When it happens
Trigger: Configuring a Job entry whose filename points to the same .kjb file as the parent job (e.g. selecting the job's own file, or a variable resolving to the parent's path), then executing/validating the entry.
Common situations: Variable like ${Internal.Job.Filename} accidentally used as the sub-job filename; copy-paste of a job that calls itself; symlink/path alias making two different strings normalize to the same file.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ColumnExists.Error.TablenameFieldMissing
- exceptionMessage
- GetSubFolders.Exception.CouldnotFindField
- GetSubFolders.Log.NoField
- GPload.Exception.DataFileMissing
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/836d7292ddb4e197.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/job/entries/job/JobEntryJob.java:1344
private void verifyRecursiveExecution( Job parentJob, JobMeta jobMeta ) throws KettleException {
if ( parentJob == null ) {
return; // OK!
}
JobMeta parentJobMeta = parentJob.getJobMeta();
if ( parentJobMeta.getName() == null && jobMeta.getName() != null ) {
return; // OK
}
if ( parentJobMeta.getName() != null && jobMeta.getName() == null ) {
return; // OK as well.
}
// Not from the repository? just verify the filename
//
if ( jobMeta.getFilename() != null && jobMeta.getFilename().equals( parentJobMeta.getFilename() ) ) {
throw new KettleException( BaseMessages.getString( PKG, "JobJobError.Recursive", jobMeta.getFilename() ) );
}
//If file has VFS reference, just verify the filename
if ( isVfsReference( jobMeta.getFilename() ) && !jobMeta.getFilename().equals( parentJobMeta.getFilename() ) ) {
return;
}
// Different directories: OK
if ( parentJobMeta.getRepositoryDirectory() == null && jobMeta.getRepositoryDirectory() != null ) {
return;
}
if ( parentJobMeta.getRepositoryDirectory() != null && jobMeta.getRepositoryDirectory() == null ) {
return;
}
if ( jobMeta.getRepositoryDirectory().getObjectId() != parentJobMeta.getRepositoryDirectory().getObjectId() ) {
return;
}
View on GitHub (pinned to f3058517a1)