pentaho/pentaho-kettle · error · KettleStepException

BaseStep.Exception.TargetStepToWriteToCantRunInMultipleCopies

BaseStep.Exception.TargetStepToWriteToCantRunInMultipleCopies

Error message

BaseStep.Exception.TargetStepToWriteToCantRunInMultipleCopies

What it means

findOutputRowSet(String targetStep) requires the target step to run in a single copy; it throws KettleStepException when targetStepMeta.getCopies() > 1. With multiple copies there are several target row sets, and writing by name alone cannot pick the right one.

Solutions

  1. Set the target step's copies to 1, or route through a single dispatcher step before the parallel copies.
  2. Use the copy-aware overload findOutputRowSet(sourceStep, sourceCopy, targetStep, targetCopy) and pick/iterate copies explicitly.
  3. Use partitioning on the target so rows are routed per partition key instead of per copy.
  4. In custom code, write via putRow to all output row sets (getOutputRowSets()) instead of one name-resolved row set.

Example fix

// before
RowSet rs = findOutputRowSet("Parallel Target"); // 4 copies
// after
for (RowSet rs : getOutputRowSets()) { rs.putRow(rowMeta, row); }
Defensive patterns

Strategy: validation

Validate before calling

StepMeta tm = transMeta.findStep(targetStepName);
if (tm != null && tm.getCopies() > 1) throw new IllegalArgumentException("Target '" + targetStepName + "' runs " + tm.getCopies() + " copies; write via getOutputRowSets()");

Try / catch

try { RowSet rs = findOutputRowSet(targetStepName); } catch (KettleStepException e) { if (e.getMessage().contains("multiple copies")) { logError("Use copy-aware output writing"); } throw e; }

Prevention

When it happens

Trigger: Calling findOutputRowSet(targetStep) where the target step is configured with copies N>1 or runs as multiple clustered copies.

Common situations: Target step parallelized via 'Change number of copies' to speed up downstream processing; clustered/slave execution duplicating the target; plugin expecting single-copy fan-out semantics.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/3411cdf485fd563a. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java:2487

   * Find output row set.
   *
   * @param targetStep the target step
   * @return the row set
   * @throws KettleStepException the kettle step exception
   */
  public RowSet findOutputRowSet( String targetStep ) throws KettleStepException {

    // Check to see that "targetStep" only runs in a single copy
    // Otherwise you'll see problems during execution.
    //
    StepMeta targetStepMeta = transMeta.findStep( targetStep );
    if ( targetStepMeta == null ) {
      throw new KettleStepException( BaseMessages.getString(
        PKG, "BaseStep.Exception.TargetStepToWriteToDoesntExist", targetStep ) );
    }

    if ( targetStepMeta.getCopies() > 1 ) {
      throw new KettleStepException( BaseMessages.getString(
        PKG, "BaseStep.Exception.TargetStepToWriteToCantRunInMultipleCopies", targetStep, Integer
          .toString( targetStepMeta.getCopies() ) ) );
    }

    return findOutputRowSet( getStepname(), getCopy(), targetStep, 0 );
  }

  /**
   * Find an output rowset in a running transformation. It will also look at the "to" step to see if this is a mapping.
   * If it is, it will find the appropriate rowset in that transformation.
   *
   * @param from
   * @param fromcopy
   * @param to
   * @param tocopy
   * @return The rowset or null if none is found.
   */
  public RowSet findOutputRowSet( String from, int fromcopy, String to, int tocopy ) {

View on GitHub (pinned to f3058517a1)