apache/skywalking · error · IllegalArgumentException

Illegal rank value {rank}, must be positive

Error message

Illegal rank value {rank}, must be positive

What it means

Percentile ranks are positional percentages (e.g. 50, 75, 99) used by AvgHistogramPercentileFunction to read values at quantiles of the accumulated histogram; a rank of 0 or a negative number is meaningless for that math. accept() validates every element of PercentileArgument.getRanks() and throws before any state is mutated.

Source

Thrown at oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/avg/AvgHistogramPercentileFunction.java:128

    @Setter
    @Column(name = RANKS, storageOnly = true)
    @BanyanDB.MeasureField
    private IntList ranks = new IntList(10);

    private boolean isCalculated = false;

    @Override
    public void accept(final MeterEntity entity, final PercentileArgument value) {
        if (dataset.size() > 0) {
            if (!value.getBucketedValues().isCompatible(dataset)) {
                throw new IllegalArgumentException(
                    "Incompatible BucketedValues [" + value + "] for current PercentileFunction[" + dataset + "]");
            }
        }

        for (final int rank : value.getRanks()) {
            if (rank <= 0) {
                throw new IllegalArgumentException("Illegal rank value " + rank + ", must be positive");
            }
        }

        if (ranks.size() > 0) {
            if (ranks.size() != value.getRanks().length) {
                throw new IllegalArgumentException(
                    "Incompatible ranks size = [" + value.getRanks().length + "] for current PercentileFunction[" + ranks
                        .size() + "]");
            } else {
                for (final int rank : value.getRanks()) {
                    if (!ranks.include(rank)) {
                        throw new IllegalArgumentException(
                            "Rank " + rank + " doesn't exist in the previous ranks " + ranks);
                    }
                }
            }
        } else {
            for (final int rank : value.getRanks()) {

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Set all ranks to positive integers (1-100 style percentiles) in the MAL rule / PercentileArgument
  2. Validate rank arrays at the producer/config boundary (reject non-positive before send)
  3. If the rank list comes from templating, default placeholders to a real rank like 50 instead of 0

Example fix

# before
  percentiles: 0,50,99   # 0 is illegal

# after
  percentiles: 50,90,99
Defensive patterns

Strategy: validation

Validate before calling

for (int rank : ranks) {
    if (rank <= 0) throw new IllegalStateException("Rank must be positive, got " + rank);
}
percentileMetric.accept(entity, new PercentileArgument(bucketedValues, ranks));

Type guard

boolean validRanks(int[] ranks) {
    for (int r : ranks) { if (r <= 0) return false; }
    return true;
}

Prevention

When it happens

Trigger: A MAL percentile rule declares ranks containing 0 or a negative value — e.g. a copied config where 0 was used as a placeholder, or arithmetic on a templated rank that produced 0/negative; an agent sends a percentile payload with a rank of 0.

Common situations: Hand-edited otel-rules YAML with placeholder ranks; templating systems injecting empty/zero values; unit tests with degenerate rank arrays.

Related errors


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