{"record":{"id":"37d4b39b22231252","repo":"pentaho/pentaho-kettle","slug":"row-metadata-and-data-unable-to-compare-rows-because-of-a","errorCode":null,"errorMessage":"Row metadata and data: unable to compare rows because of a data conversion problem","messagePattern":"Row metadata and data: unable to compare rows because of a data conversion problem","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/RowMetaAndData.java","lineNumber":117,"sourceCode":"    this.rowMeta = rowMeta;\n  }\n\n  @Override\n  public int hashCode() {\n    try {\n      return rowMeta.hashCode( data );\n    } catch ( KettleValueException e ) {\n      throw new RuntimeException(\n        \"Row metadata and data: unable to calculate hashcode because of a data conversion problem\", e );\n    }\n  }\n\n  @Override\n  public boolean equals( Object obj ) {\n    try {\n      return rowMeta.compare( data, ( (RowMetaAndData) obj ).getData() ) == 0;\n    } catch ( KettleValueException e ) {\n      throw new RuntimeException(\n        \"Row metadata and data: unable to compare rows because of a data conversion problem\", e );\n    }\n  }\n\n  public void addValue( ValueMetaInterface valueMeta, Object valueData ) {\n    if ( valueMeta.isInteger() && ( valueData instanceof ObjectId ) ) {\n      valueData = new LongObjectId( (ObjectId) valueData ).longValue();\n    }\n    data = RowDataUtil.addValueData( data, rowMeta.size(), valueData );\n    rowMeta.addValueMeta( valueMeta );\n  }\n\n  public void addValue( String valueName, int valueType, Object valueData ) {\n    ValueMetaInterface v;\n    try {\n      v = ValueMetaFactory.createValueMeta( valueName, valueType );\n    } catch ( KettlePluginException e ) {\n      v = new ValueMetaNone( valueName );","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/RowMetaAndData.java#L99-L135","documentation":"RowMetaAndData.equals() delegates row comparison to rowMeta.compare(data, other.getData()). When the two rows' metadata/values cannot be converted or compared consistently, KettleValueException is thrown and wrapped in this RuntimeException. It is thrown because equals() must not throw checked exceptions, so the conversion problem surfaces as an unchecked one.","triggerScenarios":"Calling equals() (directly or via collections like HashSet/List.contains/remove) on RowMetaAndData objects whose row metadata disagree in type or count with the stored data, so ValueMetaInterface comparison cannot convert one side.","commonSituations":"Putting RowMetaAndData objects from different repository queries into a Set; comparing rows loaded from different Pentaho/Kettle versions where a value meta type changed; rows built with mismatched addValue calls.","solutions":["Ensure both RowMetaAndData objects were built from the same RowMetaInterface (same fields, same order, same types)","Log the KettleValueException cause to identify which field/value fails conversion","Fix the value type at construction (e.g. use ValueMetaInteger for numeric data) instead of comparing mixed types","Override comparison by comparing fields explicitly instead of relying on equals()","Check for version skew between PDI client and repository schemas"],"exampleFix":"// before\nboolean same = rowMetaAndDataA.equals(rowMetaAndDataB); // RuntimeException on type mismatch\n// after\nboolean same;\ntry {\n  same = rowMetaAndDataA.equals(rowMetaAndDataB);\n} catch (RuntimeException e) {\n  log.logError(\"Row comparison failed\", e.getCause());\n  same = false;\n}","handlingStrategy":"try-catch","validationCode":"if (a.getRowMeta().size() != b.getRowMeta().size()) { /* rows not comparable */ }","typeGuard":"boolean comparable(RowMetaAndData a, RowMetaAndData b) {\n  return a != null && b != null\n    && a.getRowMeta().size() == b.getRowMeta().size()\n    && a.getRowMeta().getFieldNames().length == b.getRowMeta().getFieldNames().length;\n}","tryCatchPattern":"try {\n  boolean same = rowA.equals(rowB);\n} catch (RuntimeException e) {\n  Throwable cause = e.getCause(); // KettleValueException with field details\n  log.logError(\"Row compare failed: \" + cause.getMessage(), cause);\n}","preventionTips":["Build compared rows from the same RowMetaInterface","Never mix rows from different PDI versions in one collection","Log the cause chain when equals() throws","Prefer explicit field-by-field comparison for cross-schema rows"],"tags":["kettle","row-comparison","type-mismatch"],"backgroundTag":"type-mismatch","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"}