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" — threadedView on GitHub (pinned to 102af09b4a)
Solutions
- Read the cause (e.getCause()) and its message — the fix targets the underlying parse or metadata error, not this wrapper
- Fix the expression per the underlying error (syntax, scope/decorate rules) and retry
- 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
- Use extractMetadata as a cheap pre-check before full compile in rule-loading tooling
- Keep the underlying cause in rethrows so operators see the real error, not just the wrapper
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to compile MAL expression for metric: {}, expression:
- Load meter analyzer configs failed
- {slot} value '{numText}' exceeds the supported range (must f
- Unclosed interpolation in: {s}
- decorate() should be invoked after service()
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/01fa0ce6b5319fc6.
Report an issue: GitHub.