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
- 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() })"
- If you intended instance/endpoint scope, delete the .decorate({...}) segment entirely
- 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
- 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
- Keep decorate() only in the service-scope rule template; document one canonical example per team
- Never put decorate() in a file-level expPrefix — it would be injected into every rule including non-service scopes
- Run the MAL rule comparison test suite (dsl-scripts-test) over custom rule files in CI
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
- decorate() not supported for histogram metrics
- Failed to compile MAL expression for metric: {}, expression:
- Some configuration files of enabled rules are not found, ena
- Load meter analyzer configs failed
- {slot} value '{numText}' exceeds the supported range (must f
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/77650fd92ffdb279.
Report an issue: GitHub.