{"record":{"id":"ce55c454742f1a89","repo":"apache/skywalking","slug":"compile-failed-ce55c4","errorCode":"compile_failed","errorMessage":"MAL YAML parse failure: {t.getMessage()}","messagePattern":"MAL YAML parse failure: (.+?)","errorType":"http","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"warning","filePath":"oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/apply/MalShapeExtractor.java","lineNumber":128,"sourceCode":"\n    /**\n     * Parse a MAL YAML file and return a map {@code metricName → shape}, where metric names\n     * follow the same {@code metricPrefix + \"_\" + ruleName} formula {@code MetricConvert} uses.\n     *\n     * <p>Returns an empty map when the YAML is null/empty or has no {@code metricsRules}. Any\n     * rule whose expression fails to parse is dropped from the result — the classifier treats\n     * \"missing shape\" conservatively (falls back to the STRUCTURAL-with-over-approximation\n     * path it already has).\n     */\n    public static Map<String, MalShape> extract(final String yamlContent) {\n        if (yamlContent == null || yamlContent.isEmpty()) {\n            return Collections.emptyMap();\n        }\n        final Rule rule;\n        try (StringReader r = new StringReader(yamlContent)) {\n            rule = new Yaml().loadAs(r, Rule.class);\n        } catch (final Throwable t) {\n            throw new IllegalArgumentException(\"MAL YAML parse failure: \" + t.getMessage(), t);\n        }\n        if (rule == null || rule.getMetricsRules() == null || rule.getMetricPrefix() == null) {\n            return Collections.emptyMap();\n        }\n        final Map<String, MalShape> out = new LinkedHashMap<>();\n        for (final MetricsRule mr : rule.getMetricsRules()) {\n            if (mr.getName() == null) {\n                continue;\n            }\n            final String metricName = rule.getMetricPrefix() + \"_\" + mr.getName();\n            final String fullExpr = formatExp(rule.getExpPrefix(), rule.getExpSuffix(), mr.getExp());\n            final MalShape shape = extractShape(fullExpr);\n            if (shape != null) {\n                out.put(metricName, shape);\n            }\n        }\n        return Collections.unmodifiableMap(out);\n    }","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/apply/MalShapeExtractor.java#L110-L146","documentation":"MalShapeExtractor.extract parses MAL YAML to derive each metric's shape (for delta classification); if snakeyaml loadAs throws, it wraps the cause in IllegalArgumentException with code compile_failed. Per the javadoc, callers are expected to treat shape extraction failures conservatively — the classifier falls back to the STRUCTURAL-with-over-approximation path — so a well-behaved caller catches this rather than propagating it. If you see it raw, the calling path did not install that fallback.","triggerScenarios":"Invoking MalShapeExtractor.extract on content that is not parseable as a MAL Rule — bad YAML, LAL-flavored document, or truncated body. Note: null/empty input returns an empty map, and a parsed rule lacking metricPrefix/metricsRules also returns empty; only an actual parse throw raises this error.","commonSituations":"DeltaClassifier running classifyMal on prior content that was corrupted in storage; Feeding a manually assembled prior-content string (tests, migration scripts) that isn't valid MAL YAML; Calling extract directly from tooling without a try/catch","solutions":["If you call extract directly, wrap it and treat failure as 'unknown shape' (empty map) — matching the documented conservative contract the classifier already uses","Repair the malformed prior/new content using the wrapped cause's YAML mark","Validate content parses as Rule with metricPrefix before feeding shape extraction","In tests, build prior content via the same serializer the runtime uses instead of hand-written strings"],"exampleFix":"// before\nMap<String, MalShape> shapes = MalShapeExtractor.extract(priorContent);\n// after — honor the conservative-fallback contract\nMap<String, MalShape> shapes;\ntry {\n    shapes = MalShapeExtractor.extract(priorContent);\n} catch (final IllegalArgumentException e) {\n    shapes = Collections.emptyMap(); // unknown shape -> STRUCTURAL over-approximation\n}","handlingStrategy":"fallback","validationCode":"try (StringReader r = new StringReader(content)) { new Yaml().loadAs(r, Rule.class); } // if this throws, extract() will throw too","typeGuard":null,"tryCatchPattern":"catch (IllegalArgumentException e) when 'MAL YAML parse failure': return Collections.emptyMap() (unknown shape) and let the classifier take the conservative STRUCTURAL path — this mirrors the documented contract; log at WARN for traceability.","preventionTips":["Never call MalShapeExtractor without the empty-map fallback — it is designed to be defeatable","Keep prior-content strings sourced from the real store, not hand-typed fixtures","In migrations, re-serialize old rules through the standard parser before classification"],"tags":["mal","shape-extraction","yaml","classification"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}