pentaho/pentaho-kettle · error · KettleException

The simple mapping step needs one Mapping Output step to…

Error message

The simple mapping step needs one Mapping Output step to read from in the sub-transformation

What it means

The Simple Mapping step executes a sub-transformation and pipes rows through a Mapping Input step into the sub-transformation and out through a Mapping Output step. During prepareMappingExecution, findMappingOutput() scans the sub-transformation for Mapping Output steps; if none exist there is no step to read resulting rows from, so a KettleException is thrown.

Solutions

  1. Open the sub-transformation referenced by the Simple Mapping step and add a Mapping Output step, connecting it to the rest of the sub-transformation's stream.
  2. Verify the mapping transformation reference (file name / repository directory + entry) points at the intended mapping, not a different transformation.
  3. If multiple Mapping Output steps exist by mistake, remove all but one (SimpleMapping supports exactly one).
  4. Ensure the sub-transformation is saved and re-loaded after edits so findMappingOutput() sees the current step set.

Example fix

// Sub-transformation wrong: rows go to a normal 'Table output' step with no mapping output
// Fix: add a 'Mapping output' step and wire the sub-transformation stream into it
//   ... -> Mapping output
// then in the parent transformation's Simple Mapping step, keep the reference to that sub-transformation
Defensive patterns

Strategy: validation

Validate before calling

// Before running, verify the mapping sub-transformation has exactly one Mapping Output step
TransMeta mappingTransMeta = new TransMeta(mappingFilePath);
MappingOutput[] outputs = new MappingTransMeta(mappingTransMeta, null).findMappingOutput();
if (outputs == null || outputs.length == 0) {
  throw new IllegalStateException("Mapping sub-transformation '" + mappingFilePath + "' has no Mapping Output step");
}

Try / catch

try {
  step.init(beforeExecutionData); // SimpleMapping init
} catch (KettleException e) {
  logError("Sub-transformation is missing its Mapping Output step: " + e.getMessage());
  return false; // fail fast with a clear configuration message
}

Prevention

When it happens

Trigger: SimpleMapping.prepareMappingExecution() (invoked from step init()) calls simpleMappingData.mappingTrans.findMappingOutput() and gets a zero-length array because the referenced sub-transformation contains no Mapping Output step.

Common situations: Developer points the Simple Mapping step at a sub-transformation that was built without a Mapping Output step (e.g. a normal transformation reused as a mapping, or the sub-transformation was edited and the Mapping Output step deleted), or the wrong transformation file/repository entry is referenced so the loaded sub-trans is not the intended mapping.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/simplemapping/SimpleMapping.java:197

    if ( mappingInputs.length == 0 ) {
      throw new KettleException(
        "The simple mapping step needs one Mapping Input step to write to in the sub-transformation" );
    }
    if ( mappingInputs.length > 1 ) {
      throw new KettleException(
        "The simple mapping step does not support multiple Mapping Input steps to write to in the sub-transformation" );
    }
    simpleMappingData.mappingInput = mappingInputs[0];
    simpleMappingData.mappingInput.setConnectorSteps( new StepInterface[0], new ArrayList<MappingValueRename>(), null );

    // LogTableField readField = data.mappingTransMeta.getTransLogTable().findField(TransLogTable.ID.LINES_READ);
    // if (readField.getSubject() == null) {
    // readField.setSubject(data.mappingInput.getStepMeta());
    // }

    MappingOutput[] mappingOutputs = simpleMappingData.mappingTrans.findMappingOutput();
    if ( mappingOutputs.length == 0 ) {
      throw new KettleException(
          "The simple mapping step needs one Mapping Output step to read from in the sub-transformation" );
    }
    if ( mappingOutputs.length > 1 ) {
      throw new KettleException( "The simple mapping step does not support "
          + "multiple Mapping Output steps to read from in the sub-transformation" );
    }
    simpleMappingData.mappingOutput = mappingOutputs[0];

    // LogTableField writeField = data.mappingTransMeta.getTransLogTable().findField(TransLogTable.ID.LINES_WRITTEN);
    // if (writeField.getSubject() == null && data.mappingOutputs != null && data.mappingOutputs.length >= 1) {
    // writeField.setSubject(data.mappingOutputs[0].getStepMeta());
    // }

    // Finally, add the mapping transformation to the active sub-transformations
    // map in the parent transformation
    //
    getTrans().addActiveSubTransformation( getStepname(), simpleMappingData.mappingTrans );
  }

View on GitHub (pinned to f3058517a1)