{"record":{"id":"edcb2aa5111b5e20","repo":"pentaho/pentaho-kettle","slug":"basestep-exception-metadatadoesntmatchdatarowsize","errorCode":"BaseStep.Exception.MetadataDoesntMatchDataRowSize","errorMessage":"BaseStep.Exception.MetadataDoesntMatchDataRowSize","messagePattern":"BaseStep\\.Exception\\.MetadataDoesntMatchDataRowSize","errorType":"exception","errorClass":"KettleStepException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java","lineNumber":1679,"sourceCode":"   * @param rowMeta           the row meta\n   * @param row               the row\n   * @param nrErrors          the nr errors\n   * @param errorDescriptions the error descriptions\n   * @param fieldNames        the field names\n   * @param errorCodes        the error codes\n   * @throws KettleStepException the kettle step exception\n   */\n  public void putError( RowMetaInterface rowMeta, Object[] row, long nrErrors, String errorDescriptions,\n                        String fieldNames, String errorCodes ) throws KettleStepException {\n    getRowHandler().putError( rowMeta, row, nrErrors, errorDescriptions, fieldNames, errorCodes );\n  }\n\n\n  private void handlePutError( RowMetaInterface rowMeta, Object[] row, long nrErrors, String errorDescriptions,\n                               String fieldNames, String errorCodes ) throws KettleStepException {\n    if ( trans.isSafeModeEnabled() ) {\n      if ( rowMeta.size() > row.length ) {\n        throw new KettleStepException( BaseMessages.getString(\n          PKG, \"BaseStep.Exception.MetadataDoesntMatchDataRowSize\", Integer.toString( rowMeta.size() ), Integer\n            .toString( row != null ? row.length : 0 ) ) );\n      }\n    }\n\n    StepErrorMeta stepErrorMeta = stepMeta.getStepErrorMeta();\n\n    if ( errorRowMeta == null ) {\n      errorRowMeta = rowMeta.clone();\n\n      RowMetaInterface add = stepErrorMeta.getErrorRowMeta( nrErrors, errorDescriptions, fieldNames, errorCodes );\n      errorRowMeta.addRowMeta( add );\n    }\n\n    Object[] errorRowData = RowDataUtil.allocateRowData( errorRowMeta.size() );\n    if ( row != null ) {\n      System.arraycopy( row, 0, errorRowData, 0, rowMeta.size() );\n    }","sourceCodeStart":1661,"sourceCodeEnd":1697,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java#L1661-L1697","documentation":"In safe mode, BaseStep.handlePutError validates that the row metadata's field count matches the actual data array length before processing an error row. If rowMeta.size() > row.length, a KettleStepException with the localized message 'MetadataDoesntMatchDataRowSize' (including both sizes) is thrown. Safe mode is designed to catch exactly this kind of row/metadata inconsistency at runtime.","triggerScenarios":"Transformation run with safe mode enabled while handlePutError receives a row whose Object[] data is shorter than the declared RowMetaInterface field count — typically a step emitted rows without filling all declared fields.","commonSituations":"Custom/plugin steps that declare more fields than they produce; 'Add constants'/'User defined Java class' output rows built incorrectly; metadata changed upstream (added fields) but code paths not updated; safe mode deliberately enabled to detect such bugs.","solutions":["Fix the emitting step so each row's data array has exactly rowMeta.size() values.","Update row metadata (RowMetaInterface) to match the actual fields produced, or vice versa.","Run once without safe mode only if you accept weaker validation — better to fix the producing step.","Catch KettleStepException, parse the metadata vs data sizes in the message, and compare against the failing step's field definitions."],"exampleFix":"// before\nRowMetaInterface meta = buildMeta(); // 5 fields\nObject[] row = new Object[3]; // short row\nputRow(meta, row);\n\n// after\nObject[] row = new Object[meta.size()]; // fill all 5 fields\nputRow(meta, row);","handlingStrategy":"validation","validationCode":"// Validate row length matches metadata before putRow (safe mode invariant)\nif (rowMeta.size() > row.length) {\n  throw new IllegalStateException(\n    \"metadata=\" + rowMeta.size() + \" data=\" + row.length);\n}","typeGuard":"boolean matchesMetadata(RowMetaInterface meta, Object[] row) {\n  return row != null && row.length == meta.size();\n}","tryCatchPattern":"try {\n  putRow(rowMeta, row);\n} catch (KettleStepException e) {\n  if (e.getMessage().contains(\"MetadataDoesntMatchDataRowSize\")) {\n    logError(\"Row/metadata size mismatch: \" + e.getMessage(), e);\n  } else { throw e; }\n}","preventionTips":["Enable safe mode in test environments to catch schema bugs early","Keep emitting steps in sync with declared output fields","Rebuild row metadata whenever field lists change"],"tags":["safe-mode","row-metadata","schema-validation"],"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"}