pentaho/pentaho-kettle · error · KettleException
You can not get metrics for the target step [
Error message
You can not get metrics for the target step [
What it means
StepsMetrics refuses to sample metrics from a step that is a direct downstream target (hop successor) of the metrics step itself, because doing so would create a circular data dependency: the target step's execution depends on the metrics step completing. processRow throws this KettleException when a monitored name matches getTransMeta().getNextStepNames(getStepMeta()).
Solutions
- Remove the target step's name from the StepsMetrics monitored-steps grid.
- Restructure hops so the metrics step is not feeding the steps it monitors (monitor upstream/sibling steps only).
- If the step must be monitored, add a separate StepsMetrics instance whose output goes elsewhere.
- Validate hop topology in the step dialog before running the transformation.
Example fix
// before: monitoring a downstream hop target
// hop: Metrics -> StreamLookup ; monitored list: [StreamLookup]
meta.setStepName(new String[] { "StreamLookup" });
// after: monitor a step not downstream of Metrics
meta.setStepName(new String[] { "Table input", "Sort rows" }); Defensive patterns
Strategy: validation
Validate before calling
java.util.List<String> targets = java.util.Arrays.asList(transMeta.getNextStepNames(metricsStepMeta));
for (String monitored : meta.getStepName()) {
if (targets.contains(monitored)) {
throw new IllegalArgumentException("StepsMetrics cannot monitor downstream target step: " + monitored);
}
} Type guard
boolean noTargetOverlap(StepMeta metricsStep, TransMeta tm, StepsMetricsMeta m) {
String[] targets = tm.getNextStepNames(metricsStep);
if (targets == null) return true;
return java.util.Arrays.stream(m.getStepName()).noneMatch(n -> java.util.Arrays.asList(targets).contains(n));
} Try / catch
try {
trans.execute(null);
} catch (KettleException e) {
if (e.getMessage().startsWith("You can not get metrics for the target step [")) {
throw new IllegalStateException("StepsMetrics monitors one of its own hop targets", e);
}
throw e;
} Prevention
- Keep the StepsMetrics step's output hop disconnected from the steps it monitors.
- Review hop topology whenever you edit the monitored-steps list.
- Run a pre-execution metadata check that compares monitored names with downstream step names.
When it happens
Trigger: The monitored-steps grid lists a step that is directly connected by a hop from the StepsMetrics step, discovered at processRow time by comparing stepnames[i] against targetSteps.
Common situations: Wiring the metrics step's output into a monitored step while also listing it in the grid; reusing a monitored-step name after rewiring hops; copying step configurations between transformations where hop topology differs.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- StepsMetrics.Error.NotSteps
- You can not get metrics for the current step [
- A connection of type PALO is expected
- A server socket allocation always has to accompanied by…
- AccessInput.Exception.CouldnotFindField
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/48d693e0e0a3e66b.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/stepsmetrics/StepsMetrics.java:96
data.realsteplineswrittentfield = environmentSubstitute( meta.getStepLinesWrittenFieldName() );
data.realsteplinesupdatedfield = environmentSubstitute( meta.getStepLinesUpdatedFieldName() );
data.realsteplineserrorsfield = environmentSubstitute( meta.getStepLinesErrorsFieldName() );
data.realstepsecondsfield = environmentSubstitute( meta.getStepSecondsFieldName() );
// Get target stepnames
String[] targetSteps = getTransMeta().getNextStepNames( getStepMeta() );
data.stepInterfaces = new ConcurrentHashMap<Integer, StepInterface>();
for ( int i = 0; i < stepnrs; i++ ) {
// We can not get metrics from current step
if ( stepnames[i].equals( getStepname() ) ) {
throw new KettleException( "You can not get metrics for the current step [" + stepnames[i] + "]!" );
}
if ( targetSteps != null ) {
// We can not metrics from the target steps
for ( int j = 0; j < targetSteps.length; j++ ) {
if ( stepnames[i].equals( targetSteps[j] ) ) {
throw new KettleException( "You can not get metrics for the target step [" + targetSteps[j] + "]!" );
}
}
}
int CopyNr = Const.toInt( meta.getStepCopyNr()[i], 0 );
StepInterface si = getTrans().getStepInterface( stepnames[i], CopyNr );
if ( si != null ) {
data.stepInterfaces.put( i, getDispatcher().findBaseSteps( stepnames[i] ).get( CopyNr ) );
} else {
if ( meta.getStepRequired()[i].equals( StepsMetricsMeta.YES ) ) {
throw new KettleException( "We cannot get step [" + stepnames[i] + "] CopyNr=" + CopyNr + "!" );
}
}
}
data.outputRowMeta = new RowMeta();
meta.getFields( getTransMeta().getBowl(), data.outputRowMeta, getStepname(), null, null, this, repository,
metaStore );View on GitHub (pinned to f3058517a1)