apache/skywalking · error · IllegalArgumentException
@MALContextFunction {}.{}() first parameter must be SampleFa
Error message
@MALContextFunction {}.{}() first parameter must be SampleFamily What it means
SPI validation error from MalExtensionRegistry: a @MALContextFunction method's first parameter is missing or is not assignable to SampleFamily. The first parameter is the implicit receiver — the codegen passes the current chain value (a SampleFamily) as the first argument of the generated static call, so the signature must start with SampleFamily (or a supertype of it).
Source
Thrown at oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/v2/compiler/rt/MalExtensionRegistry.java:84
if (namespace == null || namespace.isEmpty()) {
log.warn("Skipping MalFunctionExtension with null/empty name: {}",
ext.getClass().getName());
return;
}
final Map<String, ExtensionMethod> methods = new HashMap<>();
for (final Method m : ext.getClass().getMethods()) {
if (!m.isAnnotationPresent(MALContextFunction.class)) {
continue;
}
if (!Modifier.isStatic(m.getModifiers())) {
throw new IllegalArgumentException(
"@MALContextFunction " + ext.getClass().getSimpleName()
+ "." + m.getName() + "() must be static");
}
final Class<?>[] paramTypes = m.getParameterTypes();
if (paramTypes.length == 0
|| !SampleFamily.class.isAssignableFrom(paramTypes[0])) {
throw new IllegalArgumentException(
"@MALContextFunction " + ext.getClass().getSimpleName()
+ "." + m.getName()
+ "() first parameter must be SampleFamily");
}
if (!SampleFamily.class.isAssignableFrom(m.getReturnType())) {
throw new IllegalArgumentException(
"@MALContextFunction " + ext.getClass().getSimpleName()
+ "." + m.getName()
+ "() return type must be SampleFamily");
}
final Class<?>[] extraParamTypes = new Class<?>[paramTypes.length - 1];
System.arraycopy(paramTypes, 1, extraParamTypes, 0, extraParamTypes.length);
// Validate List params use List<String> (the only List type MAL supports)
final Type[] genericTypes = m.getGenericParameterTypes();
for (int i = 1; i < genericTypes.length; i++) {
if (List.class.isAssignableFrom(extraParamTypes[i - 1])
&& genericTypes[i] instanceof ParameterizedType) {
final Type elementType =View on GitHub (pinned to 102af09b4a)
Solutions
- Make SampleFamily the first parameter: public static SampleFamily f(SampleFamily sf, <extra params...>)
- Any extra configuration parameters come after the SampleFamily one
- Rebuild and redeploy the extension jar, then restart OAP
Example fix
// before
@MALContextFunction
public static SampleFamily f(double factor) { ... }
// after
@MALContextFunction
public static SampleFamily f(SampleFamily sf, double factor) { ... } Defensive patterns
Strategy: validation
Validate before calling
Class<?>[] pts = m.getParameterTypes();
if (pts.length == 0 || !SampleFamily.class.isAssignableFrom(pts[0])) {
throw new IllegalArgumentException("First param must be SampleFamily: " + m);
} Try / catch
startup-time; fail the extension's own unit test instead of catching at runtime
Prevention
- SampleFamily always first, configuration params after
- Cover every extension with a registry-init test in CI
When it happens
Trigger: Methods like 'f()' (zero params) or 'f(String key, SampleFamily sf)' / 'f(double factor)' where SampleFamily is not paramTypes[0]. The check requires paramTypes.length > 0 and SampleFamily.class.isAssignableFrom(paramTypes[0]).
Common situations: Porting a plain utility method and adding the annotation without reordering parameters; assuming the metric is passed some other way (return value, ThreadLocal); copy-paste from a non-MAL helper class.
Related errors
- @MALContextFunction {}.{}() return type must be SampleFamily
- @MALContextFunction {}.{}() must be static
- @MALContextFunction {}.{}() List parameters must be List<Str
- Duplicate @MALContextFunction name '{}' in namespace '{}' fr
- Duplicate MAL extension namespace '{}' from {}
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/ef52752e27f08fe3.
Report an issue: GitHub.