{"record":{"id":"f875fc8b7ea59137","repo":"pentaho/pentaho-kettle","slug":"basestep-safemode-exception-mixingstoragetypes","errorCode":"BaseStep.SafeMode.Exception.MixingStorageTypes","errorMessage":"BaseStep.SafeMode.Exception.MixingStorageTypes","messagePattern":"BaseStep\\.SafeMode\\.Exception\\.MixingStorageTypes","errorType":"validation","errorClass":"KettleRowException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java","lineNumber":2193,"sourceCode":"      for ( int i = 0; i < referenceRowMeta.size(); i++ ) {\n        ValueMetaInterface referenceValue = referenceRowMeta.getValueMeta( i );\n        ValueMetaInterface compareValue = rowMeta.getValueMeta( i );\n\n        if ( !referenceValue.getName().equalsIgnoreCase( compareValue.getName() ) ) {\n          throw new KettleRowException( BaseMessages.getString(\n            PKG, \"BaseStep.SafeMode.Exception.MixingLayout\", \"\" + ( i + 1 ), referenceValue.getName()\n              + \" \" + referenceValue.toStringMeta(), compareValue.getName()\n              + \" \" + compareValue.toStringMeta() ) );\n        }\n\n        if ( referenceValue.getType() != compareValue.getType() ) {\n          throw new KettleRowException( BaseMessages.getString( PKG, \"BaseStep.SafeMode.Exception.MixingTypes\", \"\"\n            + ( i + 1 ), referenceValue.getName() + \" \" + referenceValue.toStringMeta(), compareValue.getName()\n            + \" \" + compareValue.toStringMeta() ) );\n        }\n\n        if ( referenceValue.getStorageType() != compareValue.getStorageType() ) {\n          throw new KettleRowException( BaseMessages.getString(\n            PKG, \"BaseStep.SafeMode.Exception.MixingStorageTypes\", \"\" + ( i + 1 ), referenceValue.getName()\n              + \" \" + referenceValue.toStringMeta(), compareValue.getName()\n              + \" \" + compareValue.toStringMeta() ) );\n        }\n      }\n    }\n  }\n\n  /**\n   * Gets the row from.\n   *\n   * @param rowSet the row set\n   * @return the row from\n   * @throws KettleStepException the kettle step exception\n   */\n  public Object[] getRowFrom( RowSet rowSet ) throws KettleStepException {\n    return getRowHandler().getRowFrom( rowSet );\n  }","sourceCodeStart":2175,"sourceCodeEnd":2211,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java#L2175-L2211","documentation":"safeModeChecking compares ValueMetaInterface.getStorageType() positionally; Kettle stores values either as normal Java objects (STORAGE_TYPE_NORMAL) or indexed/binary variants, and if the storage metadata differs between the reference row and the incoming row, KettleRowException is thrown. Same name, type, and arity — but the internal storage representation changed.","triggerScenarios":"Safe mode enabled; a step emits a row whose ValueMeta has a different storage metadata (e.g. STORAGE_TYPE_INDEXED from a dropdown lookup vs STORAGE_TYPE_NORMAL from a computed value) at position i.","commonSituations":"Mixing rows coming from a lookup step that returns indexed value metas with rows generated inline; plugin steps that clone value metas but override storage metadata inconsistently; serialization round-trips altering storage metadata.","solutions":["Normalize the storage metadata in the producing step: clone the ValueMetaInterface and call setStorageType(ValueMetaInterface.STORAGE_TYPE_NORMAL) before putRow.","Insert a 'Select values' step (metadata tab) which re-materializes values into normal storage between the mismatching steps.","Update the plugin step to always build ValueMeta objects with consistent storage metadata in getFields().","As a diagnostic, log rowMeta.toStringMeta() on both sides to see which field's storage metadata differs."],"exampleFix":"// before\nValueMeta vm = (ValueMeta) referenceValue.clone(); // keeps indexed storage\n// after\nValueMeta vm = (ValueMeta) referenceValue.clone();\nvm.setStorageType(ValueMetaInterface.STORAGE_TYPE_NORMAL);","handlingStrategy":"validation","validationCode":"for (int i = 0; i < rowMeta.size(); i++) {\n  if (rowMeta.getValueMeta(i).getStorageType() != referenceMeta.getValueMeta(i).getStorageType())\n    throw new IllegalStateException(\"Storage type mismatch at field \" + rowMeta.getValueMeta(i).getName());\n}","typeGuard":null,"tryCatchPattern":"try { putRow(outputRowMeta, row); } catch (KettleRowException e) { if (e.getMessage().contains(\"MixingStorageTypes\")) { logError(\"Storage metadata differs; normalize with Select values\"); } throw e; }","preventionTips":["Clone value metas from the declared layout, then override only what you need","Call setStorageType(STORAGE_TYPE_NORMAL) when building metas from lookups","Insert a Select values step to re-materialize storage between mixed sources","Log toStringMeta() of both layouts when debugging"],"tags":["kettle","pentaho","safe-mode","storage-metadata","row-metadata"],"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"}