{"record":{"id":"e6da1df491ec7768","repo":"pentaho/pentaho-kettle","slug":"unable-to-clone-row-while-copying-rows-to-multiple-target","errorCode":null,"errorMessage":"Unable to clone row while copying rows to multiple target steps","messagePattern":"Unable to clone row while copying rows to multiple target steps","errorType":"exception","errorClass":"KettleStepException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java","lineNumber":1571,"sourceCode":"\n        // To reduce stress on the locking system we are NOT going to allow\n        // the buffer to grow to its full capacity.\n        //\n        if ( isUsingThreadPriorityManagment() && !rs.isDone() && rs.size() >= upperBufferBoundary && !isStopped() ) {\n          try {\n            Thread.sleep( 0, 1 );\n          } catch ( InterruptedException e ) {\n            // Ignore sleep interruption exception\n          }\n        }\n\n        try {\n          // Loop until we find room in the target rowset\n          //\n          putRowToRowSet( rs, rowMeta, rowMeta.cloneRow( row ) );\n          incrementLinesWritten();\n        } catch ( KettleValueException e ) {\n          throw new KettleStepException( \"Unable to clone row while copying rows to multiple target steps\", e );\n        }\n      }\n\n      // set row in first output rowset\n      //\n      RowSet rs = outputRowSets.get( 0 );\n      putRowToRowSet( rs, rowMeta, row );\n      incrementLinesWritten();\n    }\n  }\n\n  private void putRowToRowSet( RowSet rs, RowMetaInterface rowMeta, Object[] row ) {\n    RowMetaInterface toBeSent;\n    RowMetaInterface metaFromRs = rs.getRowMeta();\n    if ( metaFromRs == null ) {\n      // RowSet is not initialised so far\n      toBeSent = rowMeta.clone();\n    } else {","sourceCodeStart":1553,"sourceCodeEnd":1589,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java#L1553-L1589","documentation":"When a step distributes rows to multiple target steps in copy mode, BaseStep clones each row (RowMeta.cloneRow) for every extra target. If cloning throws a KettleValueException (e.g. because a field value cannot be copied/cloned by its value metadata), it is wrapped in this KettleStepException. The row's data could not be duplicated for fan-out.","triggerScenarios":"putRow() with multiple output rowsets in copy mode while rowMeta.cloneRow(row) fails for the current row — typically due to a value type whose clone implementation cannot handle the stored object (corrupt/foreign value object in the row).","commonSituations":"Custom value types or plugin steps inserting non-standard Java objects into row fields; Kettle version mismatches where value metadata changed; rows produced by hand-built RowMeta with wrong value data.","solutions":["Inspect the chained KettleValueException cause to find which field failed to clone and fix its value data/type.","Ensure all upstream steps produce standard Kettle ValueData (ValueDataUtil) types matching their declared value metadata.","Rebuild the row metadata with 'Select values' or 'Get fields' so metadata matches actual data.","Align plugin/Kettle versions across the classpath to avoid incompatible clone implementations."],"exampleFix":"// before: row built with raw object\nObject[] row = { new CustomObject() };\nputRow(rowMeta, row);\n\n// after: use a supported type\nObject[] row = { customObject.toString() };\nputRow(rowMeta, row);","handlingStrategy":"try-catch","validationCode":"// Ensure all fields use standard Kettle value types before fan-out\nfor (int i = 0; i < rowMeta.size(); i++) {\n  if (row[i] != null && !rowMeta.getValueMeta(i).getTypeDesc().equals(\"String\") /* etc. */) {\n    // verify supported type\n  }\n}","typeGuard":"boolean isCloneable(Object[] row) {\n  return row != null && Arrays.stream(row).allMatch(v -> v == null || v instanceof String || v instanceof Number || v instanceof Date || v instanceof Boolean || v instanceof byte[]);\n}","tryCatchPattern":"try {\n  putRow(rowMeta, row);\n} catch (KettleStepException e) {\n  if (e.getMessage().contains(\"Unable to clone row\")) {\n    logError(\"Non-cloneable row value: \" + Arrays.toString(row), e);\n  } else { throw e; }\n}","preventionTips":["Use only standard Kettle value data types in rows","Keep plugin versions aligned with the Kettle engine","Match row data objects to declared RowMeta value types"],"tags":["row-cloning","type-mismatch","fan-out"],"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"}