{"record":{"id":"3b5f4d3e83b425dd","repo":"pentaho/pentaho-kettle","slug":"you-always-need-at-least-one-master-in-a-cluster-schema","errorCode":null,"errorMessage":"You always need at least one master in a cluster schema.","messagePattern":"You always need at least one master in a cluster schema\\.","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/cluster/TransSplitter.java","lineNumber":146,"sourceCode":"    Repository rep = transMeta.getRepository();\n    if ( rep != null ) {\n      rep.readTransSharedObjects( this.originalTransformation );\n    }\n\n    checkClusterConfiguration();\n\n    // FIRST : convert the dynamic master into a fixed one.\n    // This is why we copied the original transformation\n    //\n    ClusterSchema clusterSchema = this.originalTransformation.findFirstUsedClusterSchema();\n    if ( clusterSchema == null ) {\n      throw new KettleException( \"No clustering is used in this transformation.\" );\n    }\n    if ( clusterSchema.isDynamic() ) {\n      List<SlaveServer> slaveServers = clusterSchema.getSlaveServersFromMasterOrLocal();\n      SlaveServer masterSlaveServer = clusterSchema.findMaster();\n      if ( masterSlaveServer == null ) {\n        throw new KettleException( \"You always need at least one master in a cluster schema.\" );\n      }\n      slaveServers.add( 0, masterSlaveServer );\n      clusterSchema.setDynamic( false );\n      clusterSchema.setSlaveServers( slaveServers );\n    }\n  }\n\n  /**\n   * @return the originalTransformation\n   */\n  public TransMeta getOriginalTransformation() {\n    return originalTransformation;\n  }\n\n  /**\n   * @param originalTransformation\n   *          the originalTransformation to set\n   */","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/cluster/TransSplitter.java#L128-L164","documentation":"During the dynamic-cluster normalization in TransSplitter, if the cluster schema is dynamic its master is resolved via clusterSchema.findMaster(); when no slave server is flagged as master the splitter throws KettleException 'You always need at least one master in a cluster schema.' A dynamic cluster must be able to identify exactly which server will act as master.","triggerScenarios":"splitOriginalTransformation() on a transformation whose ClusterSchema.isDynamic() is true but whose slave server list contains no SlaveServer with isMaster()==true.","commonSituations":"Defining a dynamic cluster schema in Spoon without ticking 'Master' on any of its slave servers; deleting or demoting the master server in the cluster dialog; importing a cluster schema JSON missing master designation.","solutions":["Open the cluster schema in Spoon and mark one of its slave servers as master (checkbox 'is the master server').","In code, set master on one slave: slaveServers.get(0).setMaster(true) before execution.","Alternatively make the schema non-dynamic and explicitly list the master and slaves.","Validate the SlaveServer metadata (hostname/port) so findMaster() can match the defined master."],"exampleFix":"// before\nList<SlaveServer> slaves = ...; // none marked master\nClusterSchema cs = new ClusterSchema(name, slaves, ...); cs.setDynamic(true);\n// after\nslaves.get(0).setMaster(true);\nClusterSchema cs = new ClusterSchema(name, slaves, ...); cs.setDynamic(true);","handlingStrategy":"validation","validationCode":"ClusterSchema cs = transMeta.findFirstUsedClusterSchema();\nif (cs != null && cs.isDynamic() && cs.findMaster() == null) {\n  throw new IllegalStateException(\"Dynamic cluster schema '\" + cs.getName() + \"' has no master\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  splitter.splitOriginalTransformation();\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"at least one master\")) {\n    // mark a slave as master and retry\n  }\n}","preventionTips":["Always tick the master checkbox on one slave server of a dynamic cluster","Validate cluster schema metadata before submitting jobs","Keep SlaveServer definitions consistent across environment imports"],"tags":["kettle","clustering","cluster-schema","configuration"],"backgroundTag":"missing-required-config-field","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"}