pentaho/pentaho-kettle · error · KettleException
TableCompare.Exception.UnexpectedErrorComparingTables
Error message
TableCompare.Exception.UnexpectedErrorComparingTables
What it means
Generic wrapper exception thrown by the public compareTables(RowMetaInterface, Object[]) helper when any Exception occurs while reading the schema/table/key/exclude field values from the input row and delegating to the private compareTables. It wraps the original cause with the message 'Unexpected error comparing tables'.
Solutions
- Inspect the chained cause (KettleException.getCause()) to find the underlying error; the wrapper message itself is not actionable.
- Verify the reference/compare schema, table, key fields and exclude fields values in the input row are valid and non-null.
- Confirm the database connection works and the referenced tables exist and are readable.
- If calling the step API directly (as tests do), populate the input row with all required fields in the expected order.
Example fix
// before
Object[] fields = compareTables( getInputRowMeta(), r ); // throws opaque wrapper
// after: guard inputs first
if ( getInputRowMeta().indexOfValue( "compare_table" ) < 0 ) {
throw new KettleException( "compare_table field missing from input row" );
}
Object[] fields = compareTables( getInputRowMeta(), r ); Defensive patterns
Strategy: try-catch
Validate before calling
// validate all six configured fields resolve in the input row before calling compareTables
for ( String f : new String[] { refSchemaField, refTableField, cmpSchemaField, cmpTableField, keyFieldsField, excludeFieldsField } ) {
if ( inputRowMeta.indexOfValue( f ) < 0 ) throw new IllegalStateException( "missing field: " + f );
} Try / catch
try {
Object[] fields = compareTables( getInputRowMeta(), r );
} catch ( KettleException e ) {
Throwable root = e;
while ( root.getCause() != null ) root = root.getCause();
logError( "Table comparison failed, root cause: " + root.getMessage(), root );
} Prevention
- Always inspect getCause() — the wrapper message is generic.
- Pre-validate table/schema names in the input rows before running comparisons.
- Test DB connectivity with a 'Test connection' before production runs.
When it happens
Trigger: Any Exception thrown inside compareTables(rowMeta, r) — e.g. getString() failing on row indices, or the inner private compareTables throwing (SQL errors, missing tables). Called from processRow via the 'fields' local variable assignment at TableCompare.java:183.
Common situations: Database connection failures or bad table/schema names during the actual comparison; NPEs when expected row values are missing; the wrapped cause (getCause()) usually carries the real problem — often surfacing as error 2322 from the deeper overload.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- GPBulkLoaderMeta.Exception.ErrorGettingFields
- GPBulkLoaderMeta.Exception.ErrorGettingFields
- MySQLBulkLoaderMeta.Exception.ErrorGettingFields
- SynchronizeAfterMergeMeta.Exception.ErrorGettingFields
- AbsSecurityManager.ERROR_0004_UNABLE_TO_APPLY_LOGICAL_ROLES_TO_RUNTIME_ROLE
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/6c6b1ea8435fd3f2.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/tablecompare/TableCompare.java:201
Object[] fields = compareTables( getInputRowMeta(), r );
Object[] outputRowData = RowDataUtil.addRowData( r, getInputRowMeta().size(), fields );
putRow( data.outputRowMeta, outputRowData ); // copy row to output rowset(s);
return true;
}
private Object[] compareTables( RowMetaInterface rowMeta, Object[] r ) throws KettleException {
try {
String referenceSchema = getInputRowMeta().getString( r, data.refSchemaIndex );
String referenceTable = getInputRowMeta().getString( r, data.refTableIndex );
String compareSchema = getInputRowMeta().getString( r, data.cmpSchemaIndex );
String compareTable = getInputRowMeta().getString( r, data.cmpTableIndex );
String keyFields = getInputRowMeta().getString( r, data.keyFieldsIndex );
String excludeFields = getInputRowMeta().getString( r, data.excludeFieldsIndex );
return compareTables(
rowMeta, r, referenceSchema, referenceTable, compareSchema, compareTable, keyFields, excludeFields );
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString(
PKG, "TableCompare.Exception.UnexpectedErrorComparingTables" ), e );
}
}
private Object[] compareTables( RowMetaInterface rowMeta, Object[] r, String referenceSchema,
String referenceTable, String compareSchema, String compareTable, String keyFields, String excludeFields ) throws KettleException {
long nrErrors = 0L;
long nrLeftErrors = 0L;
long nrRightErrors = 0L;
long nrInnerErrors = 0L;
long nrRecordsReference = 0L;
long nrRecordsCompare = 0L;
Object[] result = new Object[6];
if ( Utils.isEmpty( referenceTable ) ) {
Object[] errorRowData = constructErrorRow( rowMeta, r, null, null, null );
putError( data.errorRowMeta, errorRowData, 1, BaseMessages.getString(View on GitHub (pinned to f3058517a1)