{"record":{"id":"4e41c26d219bdf7c","repo":"pentaho/pentaho-kettle","slug":"transsplitter-clustering-copynumberstep","errorCode":"TransSplitter.Clustering.CopyNumberStep","errorMessage":"TransSplitter.Clustering.CopyNumberStep","messagePattern":"TransSplitter\\.Clustering\\.CopyNumberStep","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/cluster/TransSplitter.java","lineNumber":572,"sourceCode":"                  //\n                  // Verify the partitioning for this slave step.\n                  // It's running in 1 or more copies depending on the number of partitions\n                  // Get the number of target partitions...\n                  //\n                  StepPartitioningMeta previousStepPartitioningMeta = previousStep.getStepPartitioningMeta();\n                  PartitionSchema previousPartitionSchema = previousStepPartitioningMeta.getPartitionSchema();\n\n                  int nrOfSourceCopies = determineNrOfStepCopies( sourceSlaveServer, previousStep );\n\n                  // Verify that the number of copies is equal to the number of slaves or 1\n                  // FIXME check this code, it no longer is relevant after the change to use determineNrOfStepCopies().\n                  // It probably wasn't working before either.\n                  //\n                  if ( masterStep.getCopies() != 1 && masterStep.getCopies() != nrOfSourceCopies ) {\n                    // this case might be handled correctly later\n                    String message = BaseMessages.getString( PKG, \"TransSplitter.Clustering.CopyNumberStep\", nrSlavesNodes,\n                        previousStep.getName(), masterStep.getName() );\n                    throw new KettleException( message );\n                  }\n\n                  // Add the required remote input and output steps to make the partitioning a reality.\n                  //\n                  for ( int sourceCopyNr = 0; sourceCopyNr < nrOfSourceCopies; sourceCopyNr++ ) {\n                    // The masterStepCopy number is increasing for each remote copy on each slave.\n                    // This makes the master distribute to each copy of the slave properly.\n                    // There is a check above to make sure that the master has either 1 copy or the same as slave*copies\n                    Integer masterStepCopyNr = masterStepCopyNumbers.poll();\n                    if ( masterStepCopyNr == null ) {\n                      masterStepCopyNr = 0;\n                    }\n\n                    // We open a port on the various slave servers...\n                    // So the source is the slave server, the target the master.\n                    //\n                    int port =\n                      getPort(","sourceCodeStart":554,"sourceCodeEnd":590,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/cluster/TransSplitter.java#L554-L590","documentation":"During splitOriginalTransformation, when generating the master copy of a clustered step, Kettle checks that the master step's copy count is 1 or equals the number of source copies. Any other combination produces an unsupported copy layout, and a localized message built from key 'TransSplitter.Clustering.CopyNumberStep' is thrown.","triggerScenarios":"splitOriginalTransformation() encounters a clustered master step where masterStep.getCopies() is neither 1 nor equal to nrOfSourceCopies (e.g. copies=3 while the source step runs 2 copies across slaves).","commonSituations":"Setting a fixed 'copies' value of 2+ on a clustered step in Spoon; changing the source step's partitioning/copy count after the clustered step's copies were tuned to an older value.","solutions":["Set the clustered master step's copies to 1 (let the cluster distribute copies).","Make the master step's copies equal the number of source copies/partitions (nrOfSourceCopies).","Remove the manual 'Change number of copies to start' setting on the step and rely on cluster/schema-driven copying."],"exampleFix":"// before\nmasterStepMeta.setCopies(3); // mismatch with 2 source copies\n// after\nmasterStepMeta.setCopies(1);","handlingStrategy":"validation","validationCode":"int nrSource = calculateStepCopies(sourceStepMeta);\nint masterCopies = masterStepMeta.getCopies();\nif (masterCopies != 1 && masterCopies != nrSource) {\n  masterStepMeta.setCopies(1);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Leave clustered steps at copies=1 unless matching the source copy count","Re-check copy settings after changing partitioning","Document why a step has multiple copies"],"tags":["kettle","clustering","step-copies","unsupported"],"backgroundTag":"unsupported-operation","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"}