pentaho/pentaho-kettle · error · KettleException

SalesforceInput.ErrorUpsert

Error message

SalesforceInput.ErrorUpsert

What it means

KettleException thrown by SalesforceConnection.upsert() when the SOAP upsert call fails. Note the original exception is embedded in the MESSAGE (BaseMessages.getString(PKG, key, e)) rather than as a cause, so the Salesforce fault text appears directly in the error message. It means none/some of the upserted records were processed at the API transport level.

Solutions

  1. Read the embedded Salesforce fault in the message — it names the exact field/record problem
  2. Verify the upsertField is a real External ID / custom field marked unique and external
  3. Check integration user has Create and Update object permissions
  4. Validate data formats (dates, picklists, numbers) against the object's field types
  5. Retry with a smaller batch to isolate record-lock/timeout issues

Example fix

// before
UpsertResult[] r = connection.upsert("ExtId__c", buffer); // field not external id
// after
// In Salesforce setup, mark ExtId__c as External ID + unique, then:
UpsertResult[] r = connection.upsert("ExtId__c", buffer);
for (UpsertResult res : r) if (!res.isSuccess()) logInsertErrors(res.getErrors());
Defensive patterns

Strategy: validation

Validate before calling

if (upsertField == null || upsertField.isEmpty()) throw new IllegalArgumentException("External ID field required for upsert"); if (sfBuffer == null || sfBuffer.length == 0) throw new IllegalArgumentException("Empty upsert buffer");

Type guard

boolean upsertReady(String extField, SObject[] buf) { return extField != null && !extField.isEmpty() && buf != null && buf.length > 0; }

Try / catch

try { results = connection.upsert(upsertField, buffer); } catch (KettleException e) { log.logError("Upsert failed: " + e.getMessage(), e); throw e; } // fault text is in e.getMessage()

Prevention

When it happens

Trigger: Calling upsert(upsertField, sfBuffer) when the binding throws: invalid external-id field, session invalid, SObject malformed, or Salesforce rejecting the batch (e.g. field infeasible for upsert).

Common situations: External ID field not marked as external ID in Salesforce, missing Write/Create permission, record-lock contention during mass upserts, malformed data types (bad date/number formats) in the incoming rows.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/b202ab16b6c6fdba. Report an issue: GitHub.

Appendix: source

Thrown at plugins/salesforce/core/src/main/java/org/pentaho/di/trans/steps/salesforce/SalesforceConnection.java:863

          for ( Field f : referenceObjectFields ) {
            if ( f.isIdLookup() && !isIdField( f ) ) {
              fieldsList.add( String.format( "%s:%s/%s", referenceTo, f.getName(), field.getRelationshipName() ) );
            }
          }
        }
      }
      return fieldsList.toArray( new String[fieldsList.size()] );
    }
    return null;
  }


  public UpsertResult[] upsert( String upsertField, SObject[] sfBuffer ) throws KettleException {
    try {
      return getBinding().upsert( upsertField, sfBuffer );
    } catch ( Exception e ) {
      throw new KettleException( BaseMessages.getString( PKG, "SalesforceInput.ErrorUpsert", e ) );
    }
  }

  public SaveResult[] insert( SObject[] sfBuffer ) throws KettleException {
    try {
      List<SObject> normalizedSfBuffer = new ArrayList<>();
      for ( SObject part : sfBuffer ) {
        if ( part != null ) {
          normalizedSfBuffer.add( part );
        }
      }
      return getBinding().create( normalizedSfBuffer.toArray( new SObject[normalizedSfBuffer.size()] ) );
    } catch ( Exception e ) {
      throw new KettleException( BaseMessages.getString( PKG, "SalesforceInput.ErrorInsert", e ) );
    }
  }

  public SaveResult[] update( SObject[] sfBuffer ) throws KettleException {

View on GitHub (pinned to f3058517a1)