apache/skywalking · critical · ModuleStartException
Auto-layer rules have duplicate name: {name}
Error message
Auto-layer rules have duplicate name: {name} What it means
Thrown during static rule load when two rules without an explicit layer (i.e. layer: auto rules) share the same name: loadStaticRules puts compiled DSLs into a name-keyed map (initAutoDsls) and a non-null previous value means a duplicate. Auto-layer rules are stored flat by name because they are selected by absence of service layer, not by a Layer key, making name uniqueness mandatory.
Source
Thrown at oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListener.java:252
* {@code RecordSinkListener.Factory.<init>}, which calls {@code moduleManager.find()}
* and asserts the manager is past prepare.
*
* <p>Idempotent against re-entry within the same boot (the Factory only stays in
* its empty post-construct state until this fires once); calling it twice on the
* same instance is a programming error.
*/
public void loadStaticRules() throws Exception {
final Map<Layer, Map<String, DSL>> initDsls = new HashMap<>();
final Map<String, DSL> initAutoDsls = new HashMap<>();
final List<LALConfig> configList = LALConfigs.load(analyzerConfig.getLalPath(), analyzerConfig.lalFiles())
.stream()
.flatMap(it -> it.getRules().stream())
.collect(Collectors.toList());
for (final LALConfig c : configList) {
final CompiledLAL compiled = compile(c);
if (compiled.layer == null) {
if (initAutoDsls.put(c.getName(), compiled.dsl) != null) {
throw new ModuleStartException(
"Auto-layer rules have duplicate name: " + c.getName());
}
} else {
final Map<String, DSL> layerDsls = initDsls.computeIfAbsent(compiled.layer, k -> new HashMap<>());
if (layerDsls.put(c.getName(), compiled.dsl) != null) {
throw new ModuleStartException(
"Layer " + compiled.layer.name() + " has already set " + c.getName() + " rule.");
}
}
// Publish per-rule debug holder into the dsl-debugging registry. sourceName, not
// sourcePath: both routes derive it through LALConfigs.stampSource, so a
// runtime-rule replace puts over the static binding without orphaning it.
LalStaticBindingHook.publish(c.getSourceName(), c.getName(), compiled.dsl.getExpression());
}
// Publish: readers from now on see the startup-complete registry.
this.dsls = initDsls;
this.autoDsls = initAutoDsls;
}View on GitHub (pinned to 102af09b4a)
Solutions
- Rename one of the two rules so every auto-layer rule name is unique
- If the rule belongs to a specific layer, add the layer: declaration — per-layer namespaces are separate
- Remove the duplicate file from lalFiles if it was left in by accident
Example fix
# before: default.yaml and my-rules.yaml both contain ruleName: default # after: my-rules.yaml ruleName: my-custom-default
Defensive patterns
Strategy: validation
Validate before calling
# Detect duplicate auto-layer rule names before deploy: # grep -h '^ruleName:' lal/*.yaml | sort | uniq -d # any output = future failure (layer-less rules)
Prevention
- Give custom rules distinctive names; never reuse 'default'
- Remember omitting layer: means auto — name accordingly
- Add a CI duplicate-name check over the whole lal catalog
When it happens
Trigger: Two LAL YAML files (or two entries in one file) both defining a rule named e.g. 'default' without a layer: declaration; copying a shipped rule file and keeping the name; a rule that omits layer: accidentally (omission means auto).
Common situations: Adding a custom rule file alongside default.yaml and reusing the name 'default'; merging rule sets from two teams; forgetting that omitting layer: puts the rule in the auto bucket.
Related errors
- Layer {} has already set {} rule.
- Failed to load static LAL rules.
- Failed to compile LAL expression: {dsl}
- Failed to load LAL config rules
- LAL rule {ruleName} layerDefinitions entry rejected: {def}
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/a9deeddc17cc07fa.
Report an issue: GitHub.