{"record":{"id":"d79abf996e763dd0","repo":"pentaho/pentaho-kettle","slug":"processfiles-error-targetfileempty","errorCode":null,"errorMessage":"ProcessFiles.Error.TargetFileEmpty","messagePattern":"ProcessFiles\\.Error\\.TargetFileEmpty","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/steps/processfiles/ProcessFiles.java","lineNumber":127,"sourceCode":"\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 ) {\n            logError( BaseMessages.getString( PKG, \"ProcessFiles.Error.TargetFileNotFile\", targetFilename ) );\n            throw new KettleException( BaseMessages.getString(\n              PKG, \"ProcessFiles.Error.TargetFileNotFile\", targetFilename ) );\n          }\n\n        } else {\n          // let's check parent folder\n          FileObject parentFolder = data.targetFile.getParent();\n          if ( !parentFolder.exists() ) {\n            if ( !meta.isCreateParentFolder() ) {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/steps/processfiles/ProcessFiles.java#L109-L145","documentation":"Thrown when operation type is not Delete and the target filename field value in the row is null or empty. The step cannot compute the destination of the copy/move without a target path, so it fails the row.","triggerScenarios":"Operation is Copy or Move and getInputRowMeta().getString(r, data.indexOfTargetFilename) yields null/\"\".","commonSituations":"Target filename field not populated by upstream step; null produced for some rows (e.g. computed filename expression returned null); field name configured points to the wrong column; renamed field in upstream mapping not propagated.","solutions":["Set the 'Target filename fieldname' in ProcessFiles to the correct non-empty field.","Fix upstream logic so the target path is always computed (e.g. concatenate target folder + filename with a proper default).","Filter out rows with empty target filename before the step.","Use error handling on the step to divert problematic rows."],"exampleFix":"// before\ntarget = concat(targetDir, nullFilename) // yields null/empty\n// after\ntarget = concat(coalesce(targetDir, \"/default/out/\"), filename)","handlingStrategy":"validation","validationCode":"// Filter rows condition before ProcessFiles:\nISNOTNULL( [targetFilename] ) && [targetFilename] <> \"\"","typeGuard":"boolean hasTargetFilename(Object[] row, RowMetaInterface meta, String field) {\n  int i = meta.indexOfValue(field);\n  return i >= 0 && row[i] != null && !row[i].toString().trim().isEmpty();\n}","tryCatchPattern":"try {\n  processRow();\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"TargetFileEmpty\")) {\n    logError(\"Empty target filename; skipping row\");\n  } else throw e;\n}","preventionTips":["Ensure the target filename expression always yields a value (COALESCE/default)","Verify the configured target field name matches the actual row field","Filter rows with empty targets before the step","Enable step error handling for graceful row-level recovery"],"tags":["pdi","kettle","empty-value","file-processing"],"backgroundTag":"empty-required-field","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"}