pentaho/pentaho-kettle · error · KettleException
SalesforceInput.Error.ObjectNotReplicateable
SalesforceInput.Error.ObjectNotReplicateable
Error message
SalesforceInput.Error.ObjectNotReplicateable
What it means
In query(), when recordsFilter is RECORDS_FILTER_UPDATED or RECORDS_FILTER_DELETED, the object must be replicateable (support getUpdated/getDeleted). The wrapper throws this KettleException when describeSObjectResult.isReplicateable() is false. Replication-based filtering is simply not available for that object.
Solutions
- Switch the retrieval filter to a date-range or 'all records' filter instead of updated/deleted for this object.
- Pick an object that is replicateable (check the replicateable flag via describe in Workbench).
- Enable replication/change-tracking for the object in Salesforce if your edition supports it.
- Implement your own delta logic by filtering on LastModifiedDate with the date-range filter instead.
Example fix
// before conn.setRecordsFilter(SalesforceConnectionUtils.RECORDS_FILTER_UPDATED); // object not replicateable // after conn.setRecordsFilter(SalesforceConnectionUtils.RECORDS_FILTER_DATE_RANGE); // use date range instead
Defensive patterns
Strategy: validation
Validate before calling
DescribeSObjectResult d = conn.getBinding().describeSObject(conn.getModule());
boolean replicationPlanned = recordsFilter == SalesforceConnectionUtils.RECORDS_FILTER_UPDATED
|| recordsFilter == SalesforceConnectionUtils.RECORDS_FILTER_DELETED;
if (replicationPlanned && (d == null || !d.isReplicateable())) {
throw new IllegalArgumentException(conn.getModule() + " is not replicateable; use a date-range filter");
} Try / catch
try {
conn.query(false);
} catch (KettleException e) {
if (e.getMessage().contains("ObjectNotReplicateable")) {
logError("getUpdated/getDeleted unsupported for " + conn.getModule());
}
throw e;
} Prevention
- Check replicateable flag before selecting updated/deleted filters.
- Fall back to LastModifiedDate range filtering for non-replicateable objects.
- Enable replication/change tracking where the edition allows.
When it happens
Trigger: query(specifyQuery=false) with recordsFilter set to updated or deleted against an object whose describe reports replicateable=false.
Common situations: Selecting 'Get updated'/'Get deleted' in the Salesforce Input step for objects that don't support replication (many custom/system objects); objects missing the change-data-capture/replication enablement; older API versions limiting replicateable flags.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- SalesforceInputDialog.ObjectNotQueryable
- Compression provider
- CsvInput.Log.OnlyLocalFilesAreSupported
- deprecated
- Erreur getting fields from module [
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/84dc0479d8095751.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/salesforce/core/src/main/java/org/pentaho/di/trans/steps/salesforce/SalesforceConnection.java:402
throw new KettleException( BaseMessages.getString( PKG, "SalesforceInput.Exception.CanNotGetBiding" ) );
}
try {
if ( !specifyQuery ) {
// check if we can query this Object
DescribeSObjectResult describeSObjectResult = getBinding().describeSObject( getModule() );
if ( describeSObjectResult == null ) {
throw new KettleException( BaseMessages.getString( PKG, "SalesforceInput.ErrorGettingObject" ) );
}
if ( !describeSObjectResult.isQueryable() ) {
throw new KettleException( BaseMessages.getString(
PKG, "SalesforceInputDialog.ObjectNotQueryable", module ) );
}
if ( this.recordsFilter == SalesforceConnectionUtils.RECORDS_FILTER_UPDATED
|| this.recordsFilter == SalesforceConnectionUtils.RECORDS_FILTER_DELETED ) {
// The object must be replicateable
if ( !describeSObjectResult.isReplicateable() ) {
throw new KettleException( BaseMessages.getString(
PKG, "SalesforceInput.Error.ObjectNotReplicateable", getModule() ) );
}
}
}
if ( getSQL() != null && log.isDetailed() ) {
log.logDetailed( BaseMessages.getString( PKG, "SalesforceInput.Log.SQLString" ) + " : " + getSQL() );
}
switch ( this.recordsFilter ) {
case SalesforceConnectionUtils.RECORDS_FILTER_UPDATED:
// Updated records ...
GetUpdatedResult updatedRecords = getBinding().getUpdated( getModule(), this.startDate, this.endDate );
if ( updatedRecords.getIds() != null ) {
int nr = updatedRecords.getIds().length;
if ( nr > 0 ) {
String[] ids = updatedRecords.getIds();View on GitHub (pinned to f3058517a1)