{"record":{"id":"e02a933a8d3f1922","repo":"pentaho/pentaho-kettle","slug":"basestep-safemode-exception-doublefieldnames","errorCode":"BaseStep.SafeMode.Exception.DoubleFieldnames","errorMessage":"BaseStep.SafeMode.Exception.DoubleFieldnames","messagePattern":"BaseStep\\.SafeMode\\.Exception\\.DoubleFieldnames","errorType":"validation","errorClass":"KettleRowException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java","lineNumber":2122,"sourceCode":"   *\n   * @param row the row\n   * @throws KettleRowException the kettle row exception\n   */\n  protected void safeModeChecking( RowMetaInterface row ) throws KettleRowException {\n    if ( row == null ) {\n      return;\n    }\n\n    if ( inputReferenceRow == null ) {\n      inputReferenceRow = row.clone(); // copy it!\n\n      // Check for double field names.\n      //\n      String[] fieldnames = row.getFieldNames();\n      Arrays.sort( fieldnames );\n      for ( int i = 0; i < fieldnames.length - 1; i++ ) {\n        if ( fieldnames[ i ].equals( fieldnames[ i + 1 ] ) ) {\n          throw new KettleRowException( BaseMessages.getString(\n            PKG, \"BaseStep.SafeMode.Exception.DoubleFieldnames\", fieldnames[ i ] ) );\n        }\n      }\n    } else {\n      safeModeChecking( inputReferenceRow, row );\n    }\n  }\n\n  /*\n   * (non-Javadoc)\n   *\n   * @see org.pentaho.di.trans.step.StepInterface#identifyErrorOutput()\n   */\n  @Override\n  public void identifyErrorOutput() {\n    if ( stepMeta.isDoingErrorHandling() ) {\n      StepErrorMeta stepErrorMeta = stepMeta.getStepErrorMeta();\n      outputRowSetsLock.writeLock().lock();","sourceCodeStart":2104,"sourceCodeEnd":2140,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java#L2104-L2140","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nfields.add(new ValueMetaString(\"id\"));\nfields.add(new ValueMetaString(\"id\")); // duplicate\n// after\nfields.add(new ValueMetaString(\"id\"));\nfields.add(new ValueMetaString(\"id_2\")); // renamed","handlingStrategy":"validation","validationCode":"String[] names = rowMeta.getFieldNames();\njava.util.Set<String> seen = new java.util.HashSet<>();\nfor (String n : names) { if (!seen.add(n.toLowerCase())) throw new IllegalStateException(\"Duplicate field: \" + n); }","typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["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"],"tags":["kettle","pentaho","safe-mode","row-metadata","duplicate-fields"],"backgroundTag":"schema-validation-failed","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"}