pinpoint-apm/pinpoint · error · IllegalArgumentException
unexpected class ${className}
Error message
unexpected class ${className} What it means
LambdaFactoryClassAdaptor.transform rewrites the bytecode of a JVM lambda factory synthetic class, expecting the class it reads to be exactly LAMBDA_FACTORY_CLASS_NAME (java/lang/invoke/LambdaMetafactory-style). If the replaced class name differs, it throws IllegalArgumentException because the adaptor was applied to the wrong class. It also warns when the method-instruction replacement count is not exactly 1.
Source
Thrown at agent-module/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryClassAdaptor.java:68
return new LambdaClassJava15();
} else if (JvmUtils.getVersion().onOrAfter(JvmVersion.JAVA_9)) {
return new LambdaClassJava9();
} else {
return new LambdaClassJava8();
}
}
public byte[] transform(byte[] bytes, LambdaClass lambdaClass) {
Objects.requireNonNull(bytes, "bytes");
final ClassReader reader = new ClassReader(bytes);
final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
final List<MethodInsn> methodInsnList = lambdaClass.getMethodInsnList();
final MethodInstReplacer methodInstReplacer = new MethodInstReplacer(writer, methodInsnList);
reader.accept(methodInstReplacer, 0);
if (!LAMBDA_FACTORY_CLASS_NAME.equals(methodInstReplacer.getClassName())) {
throw new IllegalArgumentException("unexpected class " + methodInstReplacer.getClassName());
}
if (methodInstReplacer.getTransformCount() != 1) {
logger.warn("unexpected {} invoke count {}", methodInsnList, methodInstReplacer.getTransformCount());
// dump bytecode
}
return writer.toByteArray();
}
}
View on GitHub (pinned to 744c3d3075)
Solutions
- Verify the transformer's matcher targets the exact lambda factory class name for the running JDK
- Update the plugin/profiler-optional-jdk8 module to a version compatible with the current JDK's lambda naming
- Narrow the transform matcher so only the intended synthetic lambda class is adapted
- Check the logged actual class name in the message and adjust LAMBDA_FACTORY_CLASS_NAME accordingly
Example fix
// before
if (!LAMBDA_FACTORY_CLASS_NAME.equals(methodInstReplacer.getClassName())) {
throw new IllegalArgumentException("unexpected class " + methodInstReplacer.getClassName());
}
// after
String actual = methodInstReplacer.getClassName();
if (!LAMBDA_FACTORY_CLASS_NAME.equals(actual) && !ALT_LAMBDA_FACTORY_CLASS_NAME.equals(actual)) {
logger.warn("skipping transform, unexpected class {}", actual);
return null; // leave bytecode untouched instead of failing the transform
} Defensive patterns
Strategy: try-catch
Validate before calling
byte[] transformed;
try {
transformed = adaptor.transform(loader, className, clazz, protectionDomain, bytecode);
} catch (Exception e) {
logger.warn("lambda transform skipped for {}", className, e);
return null; // return original bytecode
} Try / catch
try {
return loadTransformedBytecode(lambdaClass);
} catch (IllegalArgumentException e) {
logger.warn("unexpected class during lambda transform: {}", e.getMessage());
return originalBytecode; // degrade gracefully instead of failing class loading
} Prevention
- Pin the profiler/plugin version to one tested against your JDK's lambda class naming
- Keep transform matchers narrow so only the intended synthetic class is adapted
- Read the actual class name in the error message and compare it to LAMBDA_FACTORY_CLASS_NAME
- Wrap transform calls so failures return the original bytecode rather than breaking class loading
When it happens
Trigger: ClassFileTransformer/loadTransformedBytecode matched a class name pattern that resolved to a different runtime class name than the expected lambda factory class (e.g. a lambda subclass or a differently named synthetic class under the same matcher).
Common situations: JDK updates changing lambda synthetic class naming; lambda proxy classes cached/reused across classloaders; overly broad transform matcher matching a non-lambda class.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- defineClass fail
- unexpected {} invoke count {}
- ${className} define fail Caused by:${causeMessage}
- J9BootLoader create fail Caused by:
- initialize fail Caused by:
AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07).
Data as JSON: /api/errors/244b9c99ad1b6336.
Report an issue: GitHub.