oracle/graal · error · AnnotationFormatError
Could not parse bytes for type annotations
Error message
Could not parse bytes for type annotations
What it means
JNIMethodScope keeps a per-thread stack of active JNI scopes in a ThreadLocal. scope() returns the innermost scope but throws IllegalStateException if the thread currently has no open scope: the calling code is executing JNI helper logic outside any registered native-method call. The scope must be entered first with new JNIMethodScope(name, env) (typically try-with-resources).
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/TypeAnnotationValueParser.java:160
short length = buf.getShort();
for (int i = 0; i < length; ++i) {
buf.getShort();
buf.getShort();
buf.getShort();
}
break;
}
case CAST:
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: {
buf.getShort();
buf.get();
break;
}
default:
throw new AnnotationFormatError("Could not parse bytes for type annotations");
}
int endPos = buf.position();
byte[] targetInfo = new byte[endPos - startPos];
buf.position(startPos).get(targetInfo).position(endPos);
return targetInfo;
}
private static byte[] parseTypePath(ByteBuffer buf) {
int startPos = buf.position();
int depth = buf.get() & 0xFF;
for (int i = 0; i < depth; i++) {
buf.get();
buf.get();
}
int endPos = buf.position();
byte[] typePath = new byte[endPos - startPos];
buf.position(startPos).get(typePath).position(endPos);
return typePath;View on GitHub (pinned to a66e9ccd1d)
Solutions
- Wrap the JNI work in try (JNIMethodScope scope = new JNIMethodScope("name", env)) { ... } before any code that calls scope().
- For optional lookup use currentScope()-style access (the null-returning variant shown above scope()) and only fall back to scope() when non-null.
- Ensure the same thread that enters the scope performs the JNI work; pass the scope explicitly to helpers if needed.
Example fix
// before
JNIMethodScope s = JNIMethodScope.scope(); // throws if no scope open
handleCall(env);
// after
try (JNIMethodScope s = new JNIMethodScope("handleCall", env)) {
handleCall(env); // helpers inside may call JNIMethodScope.scope()
} Defensive patterns
Strategy: validation
Validate before calling
// Use the null-tolerant current-scope accessor before calling scope():
// (the class exposes leaf lookup; if you only have scope(), guard by tracking your own enter/exit)
boolean inScope = myScopeDepth > 0; // maintained by your try-with-resources wrapper
if (!inScope) throw new IllegalStateException("JNI helper called outside a JNIMethodScope"); Try / catch
try {
JNIMethodScope s = JNIMethodScope.scope();
} catch (IllegalStateException e) {
// scope not opened on this thread: open one (try-with-resources) and retry once
} Prevention
- Enter a JNIMethodScope at the outermost JNI boundary of each thread's call path.
- Pass the scope explicitly to helpers instead of relying on the ThreadLocal.
When it happens
Trigger: Calling JNIMethodScope.scope() (directly or via JNIUtil helpers that need the current scope) from a thread that never opened a scope; calling it after close() popped the last scope; invoking scope-dependent helpers from a helper/GC thread rather than the JNI-calling thread.
Common situations: Refactoring JNI glue so a helper runs before the scope is opened; asynchronous callbacks delivered on a different thread than the one that entered the scope; unit tests calling scope-dependent utilities without setup.
Related errors
- The VM does not expose the required Graal capability %s.
- Label used by instructions at following offsets has not been
- Could not detach thread correctly
- expected %s, got %s
- %s is not an annotation interface
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/956281395dc4e9dc.
Report an issue: GitHub.