apache/pulsar · error · IllegalArgumentException
The load shedding strategy
Error message
The load shedding strategy: ${loadBalancerLoadSheddingStrategy} can't work with the placement strategy: ${loadBalancerLoadPlacementStrategy} What it means
ModularLoadManagerImpl.initialize instantiates the configured placement strategy; if that class also implements LoadSheddingStrategy, the same instance is used for both placement and shedding, which is only allowed when loadBalancerLoadSheddingStrategy and loadBalancerLoadPlacementStrategy name the same class. Otherwise initialize throws IllegalArgumentException at broker startup.
Solutions
- Make both properties reference the same strategy class, e.g. set loadBalancerLoadSheddingStrategy and loadBalancerLoadPlacementStrategy to the same FQN.
- Or revert loadBalancerLoadPlacementStrategy to a pure placement strategy that does not implement LoadSheddingStrategy (e.g. the default).
- Remove the custom combined strategy and use the standard shedding/placement pair.
- Validate the two config values together in deployment tooling before rollout.
Example fix
# before loadBalancerLoadPlacementStrategy=org.apache.pulsar.broker.loadbalance.impl.MinimizeMemoryPlacementStrategyThatAlsoSheds loadBalancerLoadSheddingStrategy=org.apache.pulsar.broker.loadbalance.impl.ThresholdShedder # after (same class for both, or a pure placement strategy) loadBalancerLoadPlacementStrategy=org.apache.pulsar.broker.loadbalance.impl.MinimizeMemoryPlacementStrategyThatAlsoSheds loadBalancerLoadSheddingStrategy=org.apache.pulsar.broker.loadbalance.impl.MinimizeMemoryPlacementStrategyThatAlsoSheds
Defensive patterns
Strategy: validation
Validate before calling
Class<?> placement = Class.forName(conf.getLoadBalancerLoadPlacementStrategy());
if (LoadSheddingStrategy.class.isAssignableFrom(placement)
&& !conf.getLoadBalancerLoadSheddingStrategy()
.equals(conf.getLoadBalancerLoadPlacementStrategy())) {
throw new IllegalArgumentException("Shedding and placement strategies must match when placement sheds");
} Type guard
boolean isCombinedStrategy(String placementClass) {
try { return LoadSheddingStrategy.class.isAssignableFrom(Class.forName(placementClass)); }
catch (ClassNotFoundException e) { return false; }
} Try / catch
try {
new ModularLoadManagerImpl(pulsar, coordinator, checkOwnershipRequired);
} catch (IllegalArgumentException e) {
log.error("Load manager config invalid: {}", e.getMessage());
// fail startup clearly instead of masking the config mistake
} Prevention
- When placement strategy implements LoadSheddingStrategy, always set both config keys to the identical FQN.
- Diff both properties together when copying configs between clusters.
- Smoke-test broker startup with production service configuration before rollout.
When it happens
Trigger: Broker starts with loadBalancerLoadPlacementStrategy set to a class that implements LoadSheddingStrategy while loadBalancerLoadSheddingStrategy names a different class (default placement is NOT a shedding strategy, so this needs deliberate config).
Common situations: Operators copy configs between clusters and change only one of the two properties; custom placement strategies that implement both interfaces; typos where one property got a shedding class and the other kept the default.
Related errors
- Configuration field…
- must not specify ` ` to different listener.
- No authorization providers are present.
- the value in the `advertisedListeners` configure is invalid
- there are redundant configure for listener
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/876a577f3b85f148.
Report an issue: GitHub.
Appendix: source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/loadbalance/impl/ModularLoadManagerImpl.java:273
sheddingExcludedNamespaceSelectionStrategy = new RoundRobinBrokerSelector();
policies = new SimpleResourceAllocationPolicies(pulsar);
filterPipeline.add(new BrokerLoadManagerClassFilter());
filterPipeline.add(new BrokerVersionFilter());
LoadManagerShared.refreshBrokerToFailureDomainMap(pulsar, brokerToFailureDomainMap);
// register listeners for domain changes
pulsarResources.getClusterResources().getFailureDomainResources()
.registerListener(__ -> {
executors.execute(
() -> LoadManagerShared.refreshBrokerToFailureDomainMap(pulsar, brokerToFailureDomainMap));
});
if (placementStrategy instanceof LoadSheddingStrategy) {
// if the placement strategy is also a load shedding strategy
// we need to check two strategies are the same
if (!conf.getLoadBalancerLoadSheddingStrategy().equals(
conf.getLoadBalancerLoadPlacementStrategy())) {
throw new IllegalArgumentException("The load shedding strategy: "
+ conf.getLoadBalancerLoadSheddingStrategy()
+ " can't work with the placement strategy: "
+ conf.getLoadBalancerLoadPlacementStrategy());
}
// bind the load shedding strategy and the placement strategy
loadSheddingStrategy = (LoadSheddingStrategy) placementStrategy;
} else {
loadSheddingStrategy = createLoadSheddingStrategy();
}
}
public void handleDataNotification(Notification t) {
if (t.getPath().startsWith(LoadManager.LOADBALANCE_BROKERS_ROOT)) {
brokersData.listLocks(LoadManager.LOADBALANCE_BROKERS_ROOT)
.thenAccept(brokers -> {
reapDeadBrokerPreallocations(brokers);
});
View on GitHub (pinned to 820761864e)