pentaho/pentaho-kettle · error · KettleRowException
BaseStep.SafeMode.Exception.DoubleFieldnames
BaseStep.SafeMode.Exception.DoubleFieldnames
Error message
BaseStep.SafeMode.Exception.DoubleFieldnames
What it means
During safe-mode validation, BaseStep sorts the incoming row's field names and throws KettleRowException if two adjacent names are equal. Safe mode verifies every row before processing to catch row-layout corruption early. It means the step received a row containing duplicate field names, which makes field lookup ambiguous downstream.
Solutions
- Rename one of the duplicate fields in the step that produces them (Select Values / rename in the input step).
- In a SQL-based step, alias one of the colliding columns (e.g. SELECT a.id AS a_id, b.id AS b_id).
- Enable 'Include row number' with a prefix or use a 'Select values' step to de-duplicate field names before the failing step.
- If duplicates are intentional, disable safe mode — but this only hides the ambiguity; downstream steps may still misbehave.
Example fix
// before
fields.add(new ValueMetaString("id"));
fields.add(new ValueMetaString("id")); // duplicate
// after
fields.add(new ValueMetaString("id"));
fields.add(new ValueMetaString("id_2")); // renamed Defensive patterns
Strategy: validation
Validate before calling
String[] names = rowMeta.getFieldNames();
java.util.Set<String> seen = new java.util.HashSet<>();
for (String n : names) { if (!seen.add(n.toLowerCase())) throw new IllegalStateException("Duplicate field: " + n); } Try / catch
try { trans.execute(null); } catch (KettleException e) { if (e.getMessage().contains("DoubleFieldnames") || (e.getCause() instanceof KettleRowException && e.getCause().getMessage().contains("double"))) { /* fix input schema */ } else throw e; } Prevention
- Alias every joined column in SQL
- Always rename fields added by Calculator/UDJE to unique names
- Run transformations with safe mode on in test to catch schema issues early
- Assert row metadata uniqueness in unit tests of custom steps
When it happens
Trigger: Running a transformation with safe mode enabled; a step emits a RowMeta whose field names contain the exact same name twice (e.g. after two 'putField' calls with the same name, or a join producing 'id' twice).
Common situations: Database joins selecting two columns with the same name without aliases; Excel/CSV inputs where two headers collide; a User Defined Java Expression or Calculator step adding a field whose name already exists.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- BaseStep.SafeMode.Exception.MixingLayout
- BaseStep.SafeMode.Exception.MixingStorageTypes
- BaseStep.SafeMode.Exception.MixingTypes
- BaseStep.SafeMode.Exception.VaryingSize
- SalesforceUpsert.FieldNotFound
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/e02a933a8d3f1922.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java:2122
*
* @param row the row
* @throws KettleRowException the kettle row exception
*/
protected void safeModeChecking( RowMetaInterface row ) throws KettleRowException {
if ( row == null ) {
return;
}
if ( inputReferenceRow == null ) {
inputReferenceRow = row.clone(); // copy it!
// Check for double field names.
//
String[] fieldnames = row.getFieldNames();
Arrays.sort( fieldnames );
for ( int i = 0; i < fieldnames.length - 1; i++ ) {
if ( fieldnames[ i ].equals( fieldnames[ i + 1 ] ) ) {
throw new KettleRowException( BaseMessages.getString(
PKG, "BaseStep.SafeMode.Exception.DoubleFieldnames", fieldnames[ i ] ) );
}
}
} else {
safeModeChecking( inputReferenceRow, row );
}
}
/*
* (non-Javadoc)
*
* @see org.pentaho.di.trans.step.StepInterface#identifyErrorOutput()
*/
@Override
public void identifyErrorOutput() {
if ( stepMeta.isDoingErrorHandling() ) {
StepErrorMeta stepErrorMeta = stepMeta.getStepErrorMeta();
outputRowSetsLock.writeLock().lock();View on GitHub (pinned to f3058517a1)