apache/skywalking · error · UnexpectedException

Load rule {} failed

Error message

Load rule {} failed

What it means

UnexpectedException ('Load rule X failed') wrapping an IOException raised while a MAL rule's YAML text is being parsed by SnakeYAML (loadAs on a StringReader) inside parseRule. It fires at rule-load time for the named rule; the wrapped cause carries the underlying parse detail.

Source

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

    private static Rule parseRule(final String rulesetDir, final String ruleName,
                                  final String relPath, final byte[] bytes) {
        // Decode once and bind from the String: RuleSourceLines re-composes the SAME text to read
        // positional marks, which snakeyaml's bean binding discards.
        final String text = new String(bytes, StandardCharsets.UTF_8);
        try (Reader r = new StringReader(text)) {
            Rule rule = new Yaml().loadAs(r, Rule.class);
            if (rule == null) {
                return null;
            }
            rule.setName(ruleName);
            rule.setSourcePath(rulesetDir + "/"
                + (relPath == null ? ruleName + ".yaml" : relPath));
            RuleSourceLines.assign(rule, text);
            registerInlineLayers(ruleName, rule);
            return rule;
        } catch (IOException e) {
            throw new UnexpectedException("Load rule " + ruleName + " failed", e);
        }
    }

    /**
     * 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) {

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Open the named rule file and run it through a YAML linter — fix indentation, tabs, and quoting
  2. If the rule comes from a dynamic/runtime source, re-validate the stored rule text before it is pushed
  3. Compare against a known-good built-in rule file for structural keys (metric/exp/filter) — wrong key names can also derail parsing
  4. Restart/reload rules after the fix; rule loading is fail-fast at startup

Example fix

# before
metricPrefix:
  test
  rule: bad_indent
# after
metricPrefix: test
rule: fixed
Defensive patterns

Strategy: validation

Validate before calling

// CI gate: every rule file must parse as a Rule
Rule rule = new Yaml().loadAs(new String(Files.readAllBytes(p), StandardCharsets.UTF_8), Rule.class);
assert rule != null && rule.getMetricPrefix() != null;

Try / catch

catch (UnexpectedException e) { /* cause carries the YAML failure; fix the named file and reload */ }

Prevention

When it happens

Trigger: SnakeYAML raising an IOException (in practice usually a wrapped YAML stream problem such as malformed content that surfaces during reader I/O) while parsing the rule body previously read from disk or from a merged/resolver source. The rule name in the message identifies which file failed.

Common situations: Malformed YAML in a custom rule (bad indentation, tabs, unclosed quotes) that manifests during load; rule files rewritten by config-management tooling that truncated them; rules coming from a runtime-rule resolver/DB whose stored bytes are not valid YAML.

Related errors


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