apache/skywalking · critical · IllegalStateException
Duplicate RuleEngine registration for catalog '{catalog}': {
Error message
Duplicate RuleEngine registration for catalog '{catalog}': {priorClassName} vs {engineClassName} What it means
RuleEngineRegistry.register throws IllegalStateException at module start when two distinct RuleEngine implementations both claim the same catalog via supportedCatalogs(). The registry deliberately fails fast: silently dropping one engine would make catalog behavior depend on registration order, so duplicate catalog ownership is treated as a configuration error worth aborting module start. The message names the prior engine class and the new one for diagnosis.
Source
Thrown at oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/engine/RuleEngineRegistry.java:48
* to the right engine in O(1).
*
* <p>Adding a new DSL is one line in {@link
* org.apache.skywalking.oap.server.receiver.runtimerule.module.RuntimeRuleModuleProvider}:
* register the engine instance with this registry. No scheduler edit required.
*/
public final class RuleEngineRegistry {
private final Map<String, RuleEngine<?>> byCatalog = new HashMap<>();
/**
* Register {@code engine} for every catalog it claims. Throws {@link IllegalStateException}
* on duplicate catalog: two engines competing for the same catalog is a configuration error
* worth failing module start over rather than silently dropping one.
*/
public void register(final RuleEngine<?> engine) {
for (final String catalog : engine.supportedCatalogs()) {
final RuleEngine<?> prior = byCatalog.put(catalog, engine);
if (prior != null && prior != engine) {
throw new IllegalStateException(
"Duplicate RuleEngine registration for catalog '" + catalog
+ "': " + prior.getClass().getName() + " vs " + engine.getClass().getName());
}
}
}
/**
* @return the engine registered for {@code catalog}, or {@code null} if none. The scheduler
* treats {@code null} as a hard error (catalog should never be loaded if no engine claims
* it — the static rule registry filters by supported catalog at boot).
*/
public RuleEngine<?> forCatalog(final String catalog) {
return byCatalog.get(catalog);
}
/** All distinct engines, for module-start logging and lifecycle wiring. */
public Collection<RuleEngine<?>> engines() {
return byCatalog.values();View on GitHub (pinned to 102af09b4a)
Solutions
- Make catalogs disjoint: edit one engine's supportedCatalogs() to claim a catalog only it owns, or disable/remove the redundant engine module
- Check for duplicate engine classes on the classpath (mvn dependency:tree / jar overlap) and exclude the stale artifact
- If you intended to replace the default engine, exclude it from the module/provider list rather than registering both
- Restart the OAP after fixing — this throws during start and the module will not come up half-initialized
Example fix
// before
public Set<String> supportedCatalogs() { return Set.of("lal", "lal-v2"); } // 'lal' clashes with built-in
// after
public Set<String> supportedCatalogs() { return Set.of("lal-v2"); } Defensive patterns
Strategy: validation
Validate before calling
final Set<String> claimed = new HashSet<>();
for (final RuleEngine<?> e : engines) {
for (final String c : e.supportedCatalogs())
if (!claimed.add(c)) throw new ConfigException("duplicate catalog " + c);
} Try / catch
catch (IllegalStateException e) when 'Duplicate RuleEngine registration': abort startup — this is a packaging/config defect; dedupe the classpath or narrow supportedCatalogs() before restart.
Prevention
- Assert catalog disjointness in an integration test over the full engine set
- Exclude default engine modules when adding a custom engine for the same catalog
- Check mvn dependency:tree for duplicate runtime-rule artifacts before shipping custom distributions
When it happens
Trigger: Boot-time SPI/module wiring where two RuleEngine beans overlap in supportedCatalogs() — e.g. a custom engine added alongside the built-in LalRuleEngine/MalRuleEngine both declaring 'lal', or two versions of an engine class on the classpath (shaded duplicate dependency).
Common situations: Custom OAP build adding a bespoke engine for an existing catalog without excluding the default one; Dependency conflict bundling two copies of the runtime-rule engine module with different class names; Copy-pasting an engine class and forgetting to change its catalog claims
Related errors
- registry_misconfigured
- LogAnalyzerModule Factory unavailable for LAL compile of {so
- Load meter analyzer configs failed
- Failed to load GenAI configuration file.
- Failed to compile hierarchy rule: {name}, expression: {expre
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/00e5c7ba9ce6089a.
Report an issue: GitHub.