{"record":{"id":"e7f3de666b6fb600","repo":"pentaho/pentaho-kettle","slug":"salesforcedelete-error-flushbuffer","errorCode":null,"errorMessage":"SalesforceDelete.Error.FlushBuffer","messagePattern":"SalesforceDelete\\.Error\\.FlushBuffer","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"plugins/salesforce/core/src/main/java/org/pentaho/di/trans/steps/salesforcedelete/SalesforceDelete.java","lineNumber":159,"sourceCode":"          if ( checkFeedback( getLinesInput() ) ) {\n            if ( log.isDetailed() ) {\n              logDetailed( BaseMessages.getString( PKG, \"SalesforceDelete.log.LineRow\", String\n                .valueOf( getLinesInput() ) ) );\n            }\n          }\n\n        } else {\n          // there were errors during the create call, go through the\n          // errors\n          // array and write them to the screen\n\n          if ( !getStepMeta().isDoingErrorHandling() ) {\n            if ( log.isDetailed() ) {\n              logDetailed( BaseMessages.getString( PKG, \"SalesforceDelete.Found.Error\" ) );\n            }\n\n            com.sforce.soap.partner.Error err = data.deleteResult[j].getErrors()[0];\n            throw new KettleException( BaseMessages\n              .getString( PKG, \"SalesforceDelete.Error.FlushBuffer\", new Integer( j ), err.getStatusCode(), err\n                .getMessage() ) );\n\n          }\n          String errorMessage = \"\";\n          int nrErrors = data.deleteResult[j].getErrors().length;\n          for ( int i = 0; i < nrErrors; i++ ) {\n            // get the next error\n            com.sforce.soap.partner.Error err = data.deleteResult[j].getErrors()[i];\n            errorMessage +=\n              BaseMessages.getString( PKG, \"SalesforceDelete.Error.FlushBuffer\", new Integer( j ), err\n                .getStatusCode(), err.getMessage() );\n          }\n          // Simply add this row to the error row\n          if ( log.isDebug() ) {\n            logDebug( BaseMessages.getString( PKG, \"SalesforceDelete.PassingRowToErrorStep\" ) );\n          }\n          putError( getInputRowMeta(), data.outputBuffer[j], 1, errorMessage, null, \"SalesforceDelete001\" );","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/salesforce/core/src/main/java/org/pentaho/di/trans/steps/salesforcedelete/SalesforceDelete.java#L141-L177","documentation":"During flushBuffers, after executing the delete batch, the step inspects data.deleteResult for per-record failures. If the transformation is not doing error handling and a delete result contains an error, it throws a KettleException with the record index, the Salesforce status code (e.g. ENTITY_IS_DELETED, INVALID_CROSS_REFERENCE_KEY), and the error message from the first error.","triggerScenarios":"A record in the delete batch failed on the Salesforce side: already deleted, locked, insufficient access, or invalid ID — and the step has no error handling configured, so the whole step aborts.","commonSituations":"Deleting records that were already removed (double-run of the transformation); records owned by another user without delete permission; master-detail records blocked by referential constraints; invalid record IDs in the input stream.","solutions":["Enable error handling on the Delete step so failed records are routed to an error stream instead of aborting the transformation","Filter out already-deleted or invalid record IDs before the Delete step","Check the Salesforce user's delete permissions and record access (sharing rules)","Re-run only the failed records after fixing the root cause reported by the status code"],"exampleFix":"// before: no error handling, single failure aborts the run\n// step settings: error handling disabled\n// after: configure the step's error handling target so errors do not stop the transformation\nstepMeta.setSupportsErrorHandling(true); // and configure an error hop in Spoon","handlingStrategy":"try-catch","validationCode":"// pre-check for already-deleted or inaccessible records where possible\nSet<String> existingIds = salesforceQueryExistingIds(candidateIds);\nList<String> deletable = candidateIds.stream().filter(existingIds::contains).collect(Collectors.toList());","typeGuard":null,"tryCatchPattern":"try {\n  flushBuffers();\n} catch (KettleException e) {\n  logError(\"Batch delete failed; enable error handling to capture per-record errors: \" + e.getMessage());\n  throw e;\n}","preventionTips":["Enable error handling on the Salesforce Delete step so per-record failures route to an error stream","Filter out already-deleted records before deleting (idempotency check)","Verify the integration user has Delete permission on the target object","Log per-record status codes to identify systemic causes (locks, permissions, cross-reference keys)"],"tags":["salesforce","delete","api-error","batch-processing"],"backgroundTag":"api-error-response","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"}