apache/skywalking · error · IllegalStateException

decorate() not supported for histogram metrics

Error message

decorate() not supported for histogram metrics

What it means

Thrown by MALMetadataExtractor when a MAL expression chain both uses decorate({...}) and produces a histogram metric (isHistogram == true, i.e. the chain contains histogram()/histogramIncrease()-style calls). Histogram metrics have a fixed multi-bucket storage shape and cannot carry the per-service attributes that decorate() injects, so the combination is rejected at compile time when the rule is loaded.

Source

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

        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
        );
    }

    /**
     * Generates the {@code metadata()} method source.
     *

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Remove the .decorate({...}) call from the histogram rule's expression
  2. If decorate() lives in the file-level expPrefix, move it into per-rule expressions for non-histogram rules only
  3. If you need service attributes for a histogram-derived metric, compute them via tag({...}) on labels before the histogram aggregation instead

Example fix

# before
expr: request_duration.histogram().service(['svc']).decorate({ me -> me.attr0 = 'x' })

# after
expr: request_duration.histogram().service(['svc'])
Defensive patterns

Strategy: validation

Validate before calling

if (expr.contains("decorate(") && (expr.contains(".histogram("))) {
    throw new IllegalArgumentException("decorate() cannot be combined with histogram(): " + expr);
}

Try / catch

catch IllegalStateException at rule load; report the metric name and skip or fail per startup policy

Prevention

When it happens

Trigger: A rule expression like '...histogram().service([...]).decorate({ me -> ... })' — any chain where the metadata extractor marked isHistogram and a decorate MethodCall appears. Also triggered when a file-level expPrefix containing decorate() is applied to a histogram rule.

Common situations: Adding a generic decorate step to a shared expPrefix in an otel-rules file that also contains histogram rules; porting latency-percentile rules and reusing the service-attribute decoration pattern from counter/gauge rules.

Related errors


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