pentaho/pentaho-kettle · error · KettleException
ProcessFiles.Error.TargetParentFolderNotExists
Error message
ProcessFiles.Error.TargetParentFolderNotExists
What it means
Thrown when the target file's parent folder does not exist and the 'Create parent folder' option is disabled. Pentaho refuses to write/move the file into a nonexistent directory rather than silently creating it.
Solutions
- Enable 'Create parent folder' checkbox in the ProcessFiles step dialog.
- Create the target directory beforehand with a job entry (e.g. 'Create a folder' or shell mkdir -p).
- Fix the target path expression if the parent folder name is accidentally wrong (typo, wrong env variable).
- Use error handling to catch the failure and create the folder in a recovery path.
Example fix
// before (step XML) <create_parent_folder>N</create_parent_folder> // after <create_parent_folder>Y</create_parent_folder>
Defensive patterns
Strategy: validation
Validate before calling
// Guard: parent folder must exist (or be creatable) before ProcessFiles java.io.File parent = new java.io.File(targetFilename).getParentFile(); boolean ok = parent != null && (parent.exists() || parent.mkdirs());
Type guard
boolean parentFolderReady(String targetPath) {
java.io.File p = (targetPath == null) ? null : new java.io.File(targetPath).getParentFile();
return p != null && p.isDirectory();
} Try / catch
try {
processRow();
} catch (KettleException e) {
if (e.getMessage().contains("TargetParentFolderNotExists")) {
logError("Enable 'Create parent folder' or create: " + extractPath(e));
} else throw e;
} Prevention
- Check 'Create parent folder' in the step dialog when using dynamic target paths
- Pre-create target directories in the job before the transformation
- Validate environment variables used in folder paths per environment
- Test dynamic (e.g. date-based) folder expressions before production runs
When it happens
Trigger: Operation Copy/Move; data.targetFile.exists() is false; parentFolder.exists() is false; meta.isCreateParentFolder() is false.
Common situations: Target directory tree not created before the transformation runs; timestamped/dynamic folder names (e.g. /out/2026/09/13) that don't exist yet; deploy difference between dev and prod environments where folders were created manually.
Related errors
- TransExecutorDialog.Exception.UnableToFindRepositoryDirector…
- ColumnExists.Error.TablenameFieldMissing
- exceptionMessage
- GetSubFolders.Exception.CouldnotFindField
- GetSubFolders.Log.NoField
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/dd7d4a7cf853e9da.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/processfiles/ProcessFiles.java:146
}
data.targetFile = KettleVFS.getInstance( getTransMeta().getBowl() ).getFileObject( targetFilename, getTransMeta() );
if ( data.targetFile.exists() ) {
if ( log.isDetailed() ) {
logDetailed( BaseMessages.getString( PKG, "ProcessFiles.Log.TargetFileExists", targetFilename ) );
}
// check if target is really a file otherwise it could overwrite a complete folder by copy or move operations
if ( data.targetFile.getType() != FileType.FILE ) {
logError( BaseMessages.getString( PKG, "ProcessFiles.Error.TargetFileNotFile", targetFilename ) );
throw new KettleException( BaseMessages.getString(
PKG, "ProcessFiles.Error.TargetFileNotFile", targetFilename ) );
}
} else {
// let's check parent folder
FileObject parentFolder = data.targetFile.getParent();
if ( !parentFolder.exists() ) {
if ( !meta.isCreateParentFolder() ) {
throw new KettleException( BaseMessages.getString(
PKG, "ProcessFiles.Error.TargetParentFolderNotExists", parentFolder.toString() ) );
} else {
parentFolder.createFolder();
}
}
if ( parentFolder != null ) {
parentFolder.close();
}
}
}
switch ( meta.getOperationType() ) {
case ProcessFilesMeta.OPERATION_TYPE_COPY:
if ( ( ( meta.isOverwriteTargetFile() && data.targetFile.exists() ) || !data.targetFile.exists() )
&& !meta.simulate ) {
data.targetFile.copyFrom( data.sourceFile, new TextOneToOneFileSelector() );
if ( log.isDetailed() ) {
logDetailed( BaseMessages.getString(View on GitHub (pinned to f3058517a1)