apache/skywalking · error · UnexpectedException

MAL rule {} layerDefinitions entry rejected: {}

Error message

MAL rule {} layerDefinitions entry rejected: {}

What it means

UnexpectedException thrown when an inline 'layerDefinitions:' entry in a MAL rule is rejected by Layer.register — the central gatekeeper for layer registration. register() enforces reserved ordinal ranges, name uniqueness, ordinal uniqueness, and the sealed state of the layer registry; any RuntimeException from it is re-thrown with the offending rule name and the layer definition string.

Source

Thrown at oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/v2/prometheus/rule/Rules.java:187

        }
    }

    /**
     * Funnel any inline {@code layerDefinitions:} entries through {@code Layer.register}.
     * Conflict checks (reserved-range, name uniqueness, ordinal uniqueness, sealed-state) live
     * in {@code Layer.register}; failures here surface with the offending rule name in
     * the stack trace.
     */
    private static void registerInlineLayers(final String ruleName, final Rule rule) {
        final List<LayerDefinition> defs = rule.getLayerDefinitions();
        if (defs == null || defs.isEmpty()) {
            return;
        }
        for (final LayerDefinition def : defs) {
            try {
                def.register();
            } catch (RuntimeException e) {
                throw new UnexpectedException(
                    "MAL rule " + ruleName + " layerDefinitions entry rejected: " + def, e);
            }
        }
    }
}

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Read the wrapped cause from Layer.register — it states the exact conflict (duplicate name, duplicate ordinal, reserved range, or sealed registry)
  2. Change the layer name and/or ordinal in the rule's layerDefinitions so they are globally unique and outside reserved ranges
  3. If a layer with that name is already registered (e.g. created via UI), remove the inline definition and reference the existing layer instead
  4. If the registry is sealed, move the layerDefinition to a rule that loads before sealing, or register the layer through the supported config path

Example fix

# before
layerDefinitions:
  - name: custom-layer
    value: 9000   # reserved range collision
# after
layerDefinitions:
  - name: custom-layer
    value: 7000
Defensive patterns

Strategy: validation

Validate before calling

// Before registering: check uniqueness against the Layer registry you target
Optional<Layer> clashName = Layer.ALL.values().stream().filter(l -> l.name().equals(def.getName())).findAny();
Optional<Layer> clashOrdinal = Layer.ALL.values().stream().filter(l -> l.ordinal() == def.getValue()).findAny();
if (clashName.isPresent() || clashOrdinal.isPresent()) throw new IllegalStateException("layer conflict");

Try / catch

catch (UnexpectedException e) { /* message names the rule + def; cause says which Layer.register rule failed */ }

Prevention

When it happens

Trigger: A rule YAML declares layerDefinitions whose 'name' already exists, whose 'value' (ordinal) collides with an existing layer, or whose ordinal falls inside a reserved range; also when the layer registry has been sealed (rules load after boot-time sealing) so no new registrations are accepted. The full definition and cause are in the exception chain.

Common situations: Two custom rules both defining a layer with the same name or ordinal; copying a rule file and editing the layer name but not the ordinal; defining a layer in the 9000+ (or otherwise reserved) ordinal range; layer conflicts between an inline definition and layers registered from the UI/API layer endpoint.

Related errors


AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14). Data as JSON: /api/errors/bdc0d54a131e9585. Report an issue: GitHub.