pentaho/pentaho-kettle · error · KettleException
CloneRow.Log.NrClonesIsNull
Error message
CloneRow.Log.NrClonesIsNull
What it means
After emitting the original row, CloneRow reads the clone-count field from the current row via getInteger(). If that field's value is null it throws this KettleException ('NrClones is null'), since the number of clones cannot be determined.
Solutions
- Prepend a 'Replace null values' (or IF/Value Mapper) step to default the count field to 0 or a valid number before CloneRow
- Fix the upstream step so the count field is always populated (e.g. NVL/count(*) in SQL)
- Filter out or handle rows with NULL counts before CloneRow
- Coerce the field to Integer type upstream so getInteger never yields null
Example fix
// SQL upstream // before: SELECT maybe_null_cnt AS clone_count FROM t // after: SELECT NVL(maybe_null_cnt, 0) AS clone_count FROM t
Defensive patterns
Strategy: validation
Validate before calling
Object v = inputRowMeta.getInteger(row, idx);
if (v == null) {
// route row to error handling or default it before CloneRow
v = 0L;
} Try / catch
catch (KettleException e) { if (e.getMessage().contains("NrClonesIsNull")) { add Replace-null upstream and rerun; } } Prevention
- Use NVL/COALESCE in upstream SQL for count fields
- Add a Replace null values step before CloneRow
- Ensure the count field is typed Integer in the stream
When it happens
Trigger: processRow with isNrCloneInField()==true where getInputRowMeta().getInteger(r, indexOfNrCloneField) returns null — the field exists but holds NULL for this row.
Common situations: Upstream steps (table input, JSON input, optional joins) producing NULL in the count column; using a field of a type that converts to null; forgetting a default/replace-null step.
Related errors
- AddSequence.Exception.CouldNotFindNextValueForSequence
- API error. ValueMetaInterface can't be null!
- ChangeFileEncoding.Error.SourceFileIsEmpty
- CloneRow.Error.CloneFlagFieldMissing
- CloneRow.Error.CloneNumFieldMissing
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/8dfa981f43055bee.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/core/impl/src/main/java/org/pentaho/di/trans/steps/clonerow/CloneRow.java:131
outputRowData = RowDataUtil.createResizedCopy( r, data.outputRowMeta.size() );
int rowIndex = data.NrPrevFields;
if ( meta.isAddCloneFlag() ) {
// This row is not a clone but the original row
outputRowData[ rowIndex ] = false;
rowIndex++;
}
if ( meta.isAddCloneNum() ) {
// This row is the original so let's identify it as the first one (zero)
outputRowData[ rowIndex ] = 0L;
}
}
putRow( data.outputRowMeta, outputRowData ); // copy row to output rowset(s);
if ( meta.isNrCloneInField() ) {
Long nrCloneFieldValue = getInputRowMeta().getInteger( r, data.indexOfNrCloneField );
if ( nrCloneFieldValue == null ) {
throw new KettleException( BaseMessages.getString( PKG, "CloneRow.Log.NrClonesIsNull" ) );
} else {
data.nrclones = nrCloneFieldValue;
if ( log.isDebug() ) {
logDebug( BaseMessages.getString( PKG, "CloneRow.Log.NrClones", "" + data.nrclones ) );
}
}
}
for ( int i = 0; i < data.nrclones && !isStopped(); i++ ) {
// Output now all clones row
outputRowData = r.clone();
if ( data.addInfosToRow ) {
// We need here to add more infos about clone rows
outputRowData = RowDataUtil.createResizedCopy( r, data.outputRowMeta.size() );
int rowIndex = data.NrPrevFields;
if ( meta.isAddCloneFlag() ) {
// This row is a clone row
outputRowData[ rowIndex ] = true;
rowIndex++;View on GitHub (pinned to f3058517a1)