apache/skywalking · error · IllegalArgumentException

MAL expression parsing failed while injecting expPrefix: {}

Error message

MAL expression parsing failed while injecting expPrefix: {} in expression: {}

What it means

Thrown by MALScriptParser.injectExpPrefix when the base expression in a rule's exp: field fails to parse with the MAL ANTLR grammar while the compiler is splicing the file-level expPrefix (e.g. tag({tags -> ...})) into every metric source. The error listener accumulates line:column messages from ANTLR, and any syntax error aborts injection before text splicing happens.

Source

Thrown at oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/v2/compiler/MALScriptParser.java:135

        final MALLexer lexer = new MALLexer(CharStreams.fromString(exp));
        final CommonTokenStream tokens = new CommonTokenStream(lexer);
        final MALParser parser = new MALParser(tokens);
        final List<String> errors = new ArrayList<>();
        parser.removeErrorListeners();
        parser.addErrorListener(new BaseErrorListener() {
            @Override
            public void syntaxError(final Recognizer<?, ?> recognizer,
                                    final Object offendingSymbol,
                                    final int line,
                                    final int charPositionInLine,
                                    final String msg,
                                    final RecognitionException e) {
                errors.add(line + ":" + charPositionInLine + " " + msg);
            }
        });
        final MALParser.ExpressionContext tree = parser.expression();
        if (!errors.isEmpty()) {
            throw new IllegalArgumentException(
                "MAL expression parsing failed while injecting expPrefix: "
                    + String.join("; ", errors) + " in expression: " + exp);
        }
        final List<int[]> ranges = new ArrayList<>();
        collectMetricSourceRanges(tree, ranges);
        // Splice from right to left so earlier indices remain valid.
        ranges.sort(Comparator.comparingInt((int[] r) -> r[0]).reversed());
        final StringBuilder sb = new StringBuilder(exp);
        for (final int[] range : ranges) {
            final String name = sb.substring(range[0], range[1] + 1);
            sb.replace(range[0], range[1] + 1, "(" + name + "." + expPrefix + ")");
        }
        return sb.toString();
    }

    private static void collectMetricSourceRanges(final ParseTree node,
                                                  final List<int[]> ranges) {
        if (node instanceof MALParser.PrimaryContext) {

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Read the line:column in the message — it locates the syntax error in the exp: string itself
  2. Fix the expression grammar (balance parens/brackets, double-quote strings, use supported operators)
  3. Sanity-parse the expression in isolation (unit test with MALScriptParser.parse or the MalRuleLoader.formatExp helper) to separate exp errors from expPrefix errors
  4. Check for invisible characters from copy-paste (smart quotes, non-breaking spaces)

Example fix

# before
exp: http_success_request.sum(['idc'].service(['idc'])

# after
exp: http_success_request.sum(['idc']).service(['idc'])
Defensive patterns

Strategy: try-catch

Validate before calling

// fail early in tests before deploying
try {
    String combined = MALScriptParser.injectExpPrefix(exp, expPrefix);
} catch (IllegalArgumentException e) {
    throw new AssertionError("Bad exp: " + e.getMessage());
}

Try / catch

catch IllegalArgumentException around injectExpPrefix/formatExp in a rule-loading harness; report file + rule name, and fail the deployment rather than skipping the rule silently

Prevention

When it happens

Trigger: MetricConvert.formatExp calls injectExpPrefix(exp, expPrefix); it throws when the exp text has a grammar error — unbalanced parentheses, a stray character, an unsupported operator, or an identifier that does not lex as a metric source. Note this fires on the raw exp BEFORE prefix splicing, so the prefix itself is usually not the culprit.

Common situations: Hand-editing an otel-rules/meter-analyzer-config YAML and breaking the expression (missing ')', using '||' where MAL only supports specific boolean ops, smart quotes pasted from a doc); files that set a file-level expPrefix make every rule in the file go through this path, so one bad expr surfaces with this message.

Related errors


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