{"record":{"id":"129089c06a7c212c","repo":"pentaho/pentaho-kettle","slug":"processfiles-error-sourcefilenotfile","errorCode":null,"errorMessage":"ProcessFiles.Error.SourceFileNotFile","messagePattern":"ProcessFiles\\.Error\\.SourceFileNotFile","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/steps/processfiles/ProcessFiles.java","lineNumber":117,"sourceCode":"    } // End If first\n    try {\n      // get source filename\n      String sourceFilename = getInputRowMeta().getString( r, data.indexOfSourceFilename );\n\n      if ( Utils.isEmpty( sourceFilename ) ) {\n        logError( BaseMessages.getString( PKG, \"ProcessFiles.Error.SourceFileEmpty\" ) );\n        throw new KettleException( BaseMessages.getString( PKG, \"ProcessFiles.Error.SourceFileEmpty\" ) );\n      }\n      data.sourceFile = KettleVFS.getInstance( getTransMeta().getBowl() ).getFileObject( sourceFilename, getTransMeta() );\n\n      if ( !data.sourceFile.exists() ) {\n        logError( BaseMessages.getString( PKG, \"ProcessFiles.Error.SourceFileNotExist\", sourceFilename ) );\n        throw new KettleException( BaseMessages.getString(\n          PKG, \"ProcessFiles.Error.SourceFileNotExist\", sourceFilename ) );\n      }\n      if ( data.sourceFile.getType() != FileType.FILE ) {\n        logError( BaseMessages.getString( PKG, \"ProcessFiles.Error.SourceFileNotFile\", sourceFilename ) );\n        throw new KettleException( BaseMessages.getString(\n          PKG, \"ProcessFiles.Error.SourceFileNotFile\", sourceFilename ) );\n      }\n      String targetFilename = null;\n      if ( meta.getOperationType() != ProcessFilesMeta.OPERATION_TYPE_DELETE ) {\n        // get value for target filename\n        targetFilename = getInputRowMeta().getString( r, data.indexOfTargetFilename );\n\n        if ( Utils.isEmpty( targetFilename ) ) {\n          logError( BaseMessages.getString( PKG, \"ProcessFiles.Error.TargetFileEmpty\" ) );\n          throw new KettleException( BaseMessages.getString( PKG, \"ProcessFiles.Error.TargetFileEmpty\" ) );\n        }\n        data.targetFile = KettleVFS.getInstance( getTransMeta().getBowl() ).getFileObject( targetFilename, getTransMeta() );\n        if ( data.targetFile.exists() ) {\n          if ( log.isDetailed() ) {\n            logDetailed( BaseMessages.getString( PKG, \"ProcessFiles.Log.TargetFileExists\", targetFilename ) );\n          }\n          // check if target is really a file otherwise it could overwrite a complete folder by copy or move operations\n          if ( data.targetFile.getType() != FileType.FILE ) {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/steps/processfiles/ProcessFiles.java#L99-L135","documentation":"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.","triggerScenarios":"data.sourceFile.getType() != FileType.FILE after resolving sourceFilename; typically the field contains a directory path.","commonSituations":"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.","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."],"exampleFix":"// before\nGetFileNames(includeFolders=true) -> ProcessFiles\n// after\nGetFileNames(filesOnly=true, filter='*.txt') -> ProcessFiles","handlingStrategy":"validation","validationCode":"// Guard before ProcessFiles:\nnew java.io.File(sourceFilename).isFile()","typeGuard":"boolean isRegularFile(String path) {\n  java.io.File f = (path == null) ? null : new java.io.File(path);\n  return f != null && f.isFile();\n}","tryCatchPattern":"try {\n  processRow();\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"SourceFileNotFile\")) {\n    logError(\"Source path is a directory, not a file\");\n  } else throw e;\n}","preventionTips":["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"],"tags":["pdi","kettle","path-is-directory","file-processing"],"backgroundTag":"path-is-not-a-directory","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"}