pentaho/pentaho-kettle · error · KettleException
ProcessFiles.Error.SourceFileNotFile
Error message
ProcessFiles.Error.SourceFileNotFile
What it means
Thrown when the source path resolves but is not a regular file - e.g. it is a directory or other VFS FileType. Pentaho requires the source to be a real file because copy/move/delete semantics on folders are not supported by this step.
Solutions
- Point the source filename field to regular files, not directories.
- In 'Get File Names', enable 'Do not include folder name' / set 'Files/Folders' to 'Files only' or set 'Include subfolders' with a file filter.
- For directory processing, use a 'Get File Names' step to expand the directory into individual file rows first.
- Trim the path string upstream if a stray separator or folder segment was appended.
Example fix
// before GetFileNames(includeFolders=true) -> ProcessFiles // after GetFileNames(filesOnly=true, filter='*.txt') -> ProcessFiles
Defensive patterns
Strategy: validation
Validate before calling
// Guard before ProcessFiles: new java.io.File(sourceFilename).isFile()
Type guard
boolean isRegularFile(String path) {
java.io.File f = (path == null) ? null : new java.io.File(path);
return f != null && f.isFile();
} Try / catch
try {
processRow();
} catch (KettleException e) {
if (e.getMessage().contains("SourceFileNotFile")) {
logError("Source path is a directory, not a file");
} else throw e;
} Prevention
- Configure 'Get File Names' to list files only, not folders
- Expand directories into file rows with a dedicated step before processing
- Normalize/trim path strings upstream
- Preview the filename field values to spot directory paths
When it happens
Trigger: data.sourceFile.getType() != FileType.FILE after resolving sourceFilename; typically the field contains a directory path.
Common situations: Upstream 'Get File Names' step configured to include subfolder/folder names; user passed a directory expecting recursive processing; trailing path points to a folder after an upstream transformation of the path string.
Related errors
- ProcessFiles.Error.SourceFileEmpty
- ProcessFiles.Error.TargetFileEmpty
- ProcessFiles.Error.TargetFileNotFile
- API coding error: please specify the conversion metadata…
- Calculator.Error.NoNameField
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/129089c06a7c212c.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/processfiles/ProcessFiles.java:117
} // End If first
try {
// get source filename
String sourceFilename = getInputRowMeta().getString( r, data.indexOfSourceFilename );
if ( Utils.isEmpty( sourceFilename ) ) {
logError( BaseMessages.getString( PKG, "ProcessFiles.Error.SourceFileEmpty" ) );
throw new KettleException( BaseMessages.getString( PKG, "ProcessFiles.Error.SourceFileEmpty" ) );
}
data.sourceFile = KettleVFS.getInstance( getTransMeta().getBowl() ).getFileObject( sourceFilename, getTransMeta() );
if ( !data.sourceFile.exists() ) {
logError( BaseMessages.getString( PKG, "ProcessFiles.Error.SourceFileNotExist", sourceFilename ) );
throw new KettleException( BaseMessages.getString(
PKG, "ProcessFiles.Error.SourceFileNotExist", sourceFilename ) );
}
if ( data.sourceFile.getType() != FileType.FILE ) {
logError( BaseMessages.getString( PKG, "ProcessFiles.Error.SourceFileNotFile", sourceFilename ) );
throw new KettleException( BaseMessages.getString(
PKG, "ProcessFiles.Error.SourceFileNotFile", sourceFilename ) );
}
String targetFilename = null;
if ( meta.getOperationType() != ProcessFilesMeta.OPERATION_TYPE_DELETE ) {
// get value for target filename
targetFilename = getInputRowMeta().getString( r, data.indexOfTargetFilename );
if ( Utils.isEmpty( targetFilename ) ) {
logError( BaseMessages.getString( PKG, "ProcessFiles.Error.TargetFileEmpty" ) );
throw new KettleException( BaseMessages.getString( PKG, "ProcessFiles.Error.TargetFileEmpty" ) );
}
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 ) {View on GitHub (pinned to f3058517a1)