apache/skywalking · error · IllegalStateException

decorate() should be invoked after service()

Error message

decorate() should be invoked after service()

What it means

Thrown by MALMetadataExtractor during compile-time AST analysis when a MAL expression chain contains a decorate({...}) call but the declared scope is not service scope. decorate() attaches service-level attributes via a DecorateFunction closure, which is only meaningful when the metric is aggregated into Service entities, so the extractor rejects any other scope (ServiceInstance, Endpoint, ServiceRelation, All). It fires at OAP startup while compiling the rule, before any data is processed.

Source

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

            }
        }

        // Validate decorate() usage
        boolean hasDecorate = false;
        for (final List<MALExpressionModel.MethodCall> chain : allChains) {
            for (final MALExpressionModel.MethodCall mc : chain) {
                if ("decorate".equals(mc.getName())) {
                    hasDecorate = true;
                    break;
                }
            }
            if (hasDecorate) {
                break;
            }
        }
        if (hasDecorate) {
            if (scopeType != null && scopeType != ScopeType.SERVICE) {
                throw new IllegalStateException(
                    "decorate() should be invoked after service()");
            }
            if (isHistogram) {
                throw new IllegalStateException(
                    "decorate() not supported for histogram metrics");
            }
        }

        return new ExpressionMetadata(
            new ArrayList<>(sampleNames),
            scopeType,
            scopeLabels,
            aggregationLabels,
            downsampling,
            isHistogram,
            percentiles
        );
    }

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Move/keep decorate() only in expressions whose expSuffix is service([...]), e.g. "expr: http_success_request.sum(['idc']).service(['idc'], Layer.GENERAL).decorate({ me -> me.attr0 = me.layer.name() })"
  2. If you intended instance/endpoint scope, delete the .decorate({...}) segment entirely
  3. Check the file-level expPrefix: if it contains decorate(), it is injected into every rule in the file, so it conflicts with any rule not using service() scope — scope it per-rule instead
  4. Restart OAP after fixing the YAML; the error is raised at rule compilation, not at runtime

Example fix

# before (rule YAML)
expr: http_success_request.sum(['idc']).serviceInstance(['idc']).decorate({ me -> me.attr0 = 'x' })

# after
expr: http_success_request.sum(['idc']).serviceInstance(['idc'])
# or, if service attributes are wanted:
expr: http_success_request.sum(['idc']).service(['idc']).decorate({ me -> me.attr0 = 'x' })
Defensive patterns

Strategy: validation

Validate before calling

// before compiling, assert the rule's scope if it uses decorate
String expr = rule.getExp();
if (expr.contains("decorate(")) {
    boolean serviceScoped = expr.matches("(?s).*\\.service\\(.*\\.decorate\\(.*");
    if (!serviceScoped) {
        throw new IllegalArgumentException("decorate() requires service() scope: " + expr);
    }
}

Try / catch

catch (IllegalStateException e) when starting the analyzer; log rule name + expression and fail OAP startup fast so the misconfiguration is visible immediately

Prevention

When it happens

Trigger: A MAL rule whose expression uses decorate({ me -> ... }) together with an expSuffix scope function other than service(...), e.g. '...sum([\'idc\']).serviceInstance([\'idc\']).decorate({ me -> me.attr0 = ... })', or where a file-level expPrefix injects decorate into a chain that ends in a non-service scope. Concretely: hasDecorate is true after scanning the method chain AND scopeType != null AND scopeType != ScopeType.SERVICE.

Common situations: Copying an existing service-scope decorate rule (e.g. from the SkyWalking service-level dashboards) and changing expSuffix to serviceInstance or endpoint while forgetting to remove the decorate() call; upgrading from v1 Groovy engine where decorate was silently tolerated on other scopes; hand-editing otel-rules YAML files.

Related errors


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