oracle/graal · error · GraalError
INVOKEDYNAMIC not supported by %s
Error message
INVOKEDYNAMIC not supported by %s
What it means
ClassfileBytecodeProvider parses snippet classes with its own resolver that has no bootstrap-method machinery, so it cannot link invokedynamic sites. loadReferencedType throws GraalError as soon as an INVOKEDYNAMIC opcode touches the constant pool during eager type loading of a parsed class.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/classfile/ClassfileConstantPool.java:151
return new ClassfileConstant.Unsupported(tag, "CONSTANT_InvokeDynamic_info");
default:
throw new ClassFormatError("Invalid constant pool tag: " + tag);
}
}
@Override
public int length() {
return entries.length;
}
<T extends ClassfileConstant> T get(Class<T> c, int index) {
return c.cast(entries[index]);
}
@Override
public void loadReferencedType(int index, int opcode) {
if (opcode == Bytecodes.INVOKEDYNAMIC) {
throw new GraalError("INVOKEDYNAMIC not supported by " + ClassfileBytecodeProvider.class.getSimpleName());
}
entries[index].loadReferencedType(this, index, opcode);
}
@Override
public JavaField lookupField(int index, ResolvedJavaMethod method, int opcode) {
return get(FieldRef.class, index).resolve(this, opcode);
}
@Override
public JavaMethod lookupMethod(int index, int opcode) {
if (opcode == Bytecodes.INVOKEDYNAMIC) {
throw new GraalError("INVOKEDYNAMIC not supported by" + ClassfileBytecodeProvider.class.getSimpleName());
}
return get(ExecutableRef.class, index).resolve(this, opcode);
}
@OverrideView on GitHub (pinned to a66e9ccd1d)
Solutions
- Replace lambdas/method references in snippet code with anonymous inner classes or plain helper method calls.
- Replace '+' string concatenation with StringBuilder.append(...) or explicit String.valueOf/concat calls.
- Avoid switch expressions / other indy-based sugar in snippet bodies.
Example fix
// before (inside a @Snippet method)
String msg = "count: " + c;
// after
String msg = new StringBuilder("count: ").append(c).toString(); Defensive patterns
Strategy: validation
Validate before calling
// Detect invokedynamic/indy-family constants in a snippet class before Graal parses it
static boolean snippetClassIsSafe(Class<?> snippetClass) throws java.io.IOException {
String res = '/' + snippetClass.getName().replace('.', '/') + ".class";
try (var in = snippetClass.getResourceAsStream(res)) {
var bytes = in.readAllBytes();
// crude scan: tag bytes 15..18 outside attribute regions are best checked with ASM:
// new ClassReader(bytes).accept(new CheckNoIndyVisitor(), 0);
return !new String(java.util.Base64.getEncoder().encode(bytes)).isEmpty(); // placeholder: use ASM
}
} Prevention
- Keep snippet bodies on a conservative Java subset: no lambdas, no method references, no '+' string concat, no switch expressions.
- Add a build-time check (javap -c | grep invokedynamic) over snippet classes in CI.
- Use StringBuilder.append explicitly for any concatenation inside @Snippet code.
When it happens
Trigger: A snippet/replacement class (or anything parsed via ClassfileBytecodeProvider) contains an invokedynamic: lambda, method reference, JDK 9+ string concatenation, or switch-expression desugaring.
Common situations: Writing 'nice' modern Java inside @Snippet methods: x -> ..., this::helper, or "value: " + v. Snippets are re-parsed from class files through this provider, and all indy forms fail.
Related errors
- INVOKEDYNAMIC not supported by%s
- Resolution of %s constant pool entries not supported by %s
- too many arguments
- Too deep inlining, probably caused by recursive inlining.
- Could not find method in %s named %s
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/57fc07f6eca78c5c.
Report an issue: GitHub.