apache/skywalking · error · IllegalArgumentException

Function {} doesn't inherit from Metrics.

Error message

Function {} doesn't inherit from Metrics.

What it means

MeterSystem.create() generates a Metrics subclass at runtime (Javassist) for every metric declared by a MAL rule. The function class resolved from the FunctionRegister must both implement AcceptableValue<T> and inherit from org.apache.skywalking.oap.server.core.analysis.metrics.Metrics, because the generated class extends it and is pushed into the stream-processing pipeline. This IllegalArgumentException fires when the registered function class fails the Metrics.class.isAssignableFrom check.

Source

Thrown at oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterSystem.java:243

                    } else {
                        acceptance = arguments[0].getTypeName();
                    }
                }
                if (foundDataType) {
                    break;
                }
            }
        }
        if (!foundDataType) {
            throw new IllegalArgumentException("Function " + functionName
                + " requires <" + acceptance + "> in AcceptableValue"
                + " but using " + dataType.getName() + " in the creation");
        }
        final CtClass parentClass;
        try {
            parentClass = pool.get(meterFunction.getCanonicalName());
            if (!Metrics.class.isAssignableFrom(meterFunction)) {
                throw new IllegalArgumentException(
                    "Function " + functionName + " doesn't inherit from Metrics.");
            }
        } catch (NotFoundException e) {
            throw new IllegalArgumentException("Function " + functionName + " can't be found by javaassist.");
        }
        final String className = formatName(metricsName);
        // Prototype-first short-circuit (fires on runtime FILTER_ONLY re-apply). Every
        // runtime apply hands in a fresh {@code ClassPool}, so the pool-based existence
        // check below cannot see a Metrics class the previous apply defined in a now-dead
        // pool. Without this guard, every FILTER_ONLY update generated a new Metrics class,
        // new MetricsStreamProcessor workers, and a new prototype that shadowed the old
        // one in {@link #meterPrototypes} — a removeMetric by name could only tear down the
        // latest generation, leaving prior workers + classloaders pinned forever. Match on
        // scope + data type + function class; any of those differing is a genuine shape
        // change and the existing IllegalArgumentException on the pool path fires below.
        final MeterDefinition existingDefinition = meterPrototypes.get(metricsName);
        if (existingDefinition != null
            && existingDefinition.getScopeType() == type

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Make the custom function class extend one of the abstract bases in org.apache.skywalking.oap.server.core.analysis.meter.function (e.g. AvgFunction, SumFunction) or otherwise extend a Metrics subclass while also implementing AcceptableValue<T>
  2. Verify the registration entry: FunctionRegister must map the MAL function name to the class that is both a Metrics and an AcceptableValue
  3. Rebuild the custom function jar against the exact OAP server version deployed, then place it in oap-libs/ so the class hierarchy matches

Example fix

// before
public class MyCounter implements AcceptableValue<Long> { ... }
FunctionRegister.register("mycounter", MyCounter.class);

// after
public class MyCounter extends CounterFunction implements AcceptableValue<Long> { ... }
// CounterFunction already extends Metrics; the isAssignableFrom check now passes
Defensive patterns

Strategy: validation

Validate before calling

// before registering/using a custom meter function
if (!Metrics.class.isAssignableFrom(funcClass)
        || !AcceptableValue.class.isAssignableFrom(funcClass)) {
    throw new IllegalStateException(funcClass + " must extend Metrics and implement AcceptableValue");
}
FunctionRegister.register(functionName, funcClass);

Type guard

boolean isValidMeterFunction(Class<?> c) {
    return Metrics.class.isAssignableFrom(c)
        && AcceptableValue.class.isAssignableFrom(c);
}

Prevention

When it happens

Trigger: A MAL/LAL rule names a function whose registered implementation class implements AcceptableValue but does not extend Metrics; a custom meter function was registered into FunctionRegister with an incomplete class hierarchy (e.g. only implementing the interface); a custom function was compiled against an old SkyWalking version where the hierarchy differed.

Common situations: Writing a custom MAL function plugin: developers implement AcceptableValue but forget to extend a base class like AvgFunction; deploying a custom function jar built against an incompatible SkyWalking version; misregistered function name that collides with another non-Metrics entry.

Related errors


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