apache/skywalking · error · IllegalStateException

Failed to parse MAL expression for metadata: {}

Error message

Failed to parse MAL expression for metadata: {}

What it means

Wrapper exception from DSL.extractMetadata: it runs MALScriptParser.parse(expression) followed by MALMetadataExtractor.extractMetadata(ast), and any Exception from either (ANTLR syntax errors, invalid decorate()/scope/histogram combinations) is rethrown as IllegalStateException with the offending expression text. Its purpose is to give callers one exception type to catch when they only need metadata for rule classification (e.g. deciding FILTER_ONLY vs STRUCTURAL storage shape).

Source

Thrown at oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/v2/dsl/DSL.java:89

     * the shared {@link #GENERATOR} singleton (startup path, unchanged). Passing null for
     * only one of the two is treated as "startup path" — there is no half-isolated mode.
     */
    /**
     * Extract compile-time {@link ExpressionMetadata} from a MAL expression string without
     * running Javassist codegen. Returns scope type, sample names, aggregation labels,
     * histogram flag + percentiles, and downsampling — the inputs the runtime-rule classifier
     * needs to derive the storage shape tuple {@code (functionName, scopeType)} for a metric
     * and decide FILTER_ONLY vs STRUCTURAL.
     *
     * <p>Throws {@link IllegalStateException} on parse failure — wraps the upstream ANTLR
     * error listener so callers have a single exception type to catch.
     */
    public static ExpressionMetadata extractMetadata(final String expression) {
        try {
            final MALExpressionModel.Expr ast = MALScriptParser.parse(expression);
            return MALMetadataExtractor.extractMetadata(ast);
        } catch (final Exception e) {
            throw new IllegalStateException(
                "Failed to parse MAL expression for metadata: " + expression, e);
        }
    }

    public static Expression parse(final String metricName,
                                   final String expression,
                                   final DslSourceRef sourceRef,
                                   final ClassPool pool,
                                   final ClassLoader targetClassLoader) {
        try {
            final MalExpression malExpr;
            if (pool != null && targetClassLoader != null) {
                // Per-file generator: one instance per compile is fine — it's just a thin
                // orchestrator over ClassPool. Prevents cross-contamination of classNameHint /
                // sourceRef state that the shared GENERATOR carries between calls.
                final MALClassGenerator perFile = new MALClassGenerator(pool, targetClassLoader);
                perFile.setSourceRef(sourceRef);
                // The verbatim MAL expression text is the rule's "content" — threaded

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Read the cause (e.getCause()) and its message — the fix targets the underlying parse or metadata error, not this wrapper
  2. Fix the expression per the underlying error (syntax, scope/decorate rules) and retry
  3. If writing a caller of extractMetadata, catch IllegalStateException and log the expression string for context

Example fix

// before
ExpressionMetadata md = DSL.extractMetadata(rule.getExp()); // throws on bad rule

// after
ExpressionMetadata md;
try {
    md = DSL.extractMetadata(rule.getExp());
} catch (IllegalStateException e) {
    throw new IllegalStateException("Rule " + rule.getMetricName() + " invalid: " + e.getMessage(), e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

ExpressionMetadata md;
try {
    md = DSL.extractMetadata(expression);
} catch (IllegalStateException e) {
    // handle invalid rule: log + skip/fail per policy
    throw e;
}

Try / catch

catch IllegalStateException once around extractMetadata, then inspect getCause() to distinguish syntax vs semantic (decorate/scope) failures; always carry the rule name into the log

Prevention

When it happens

Trigger: Calling DSL.extractMetadata(expression) with any malformed or semantically invalid expression — the underlying cause can be error 49/50 (parse failure) or 40/41 (decorate misuse). The original exception is preserved as the cause.

Common situations: OAP startup classifying MAL rules for storage: a bad rule in an otel-rules file surfaces through this wrapper; tooling or tests that pre-validate expressions via extractMetadata before full compilation.

Understand the failure class

Related errors


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