oracle/graal · error · GraalError
Label used by instructions at following offsets has not been
Error message
Label used by instructions at following offsets has not been bound: %s
What it means
close() on the outermost JNIMethodScope (parent == null) asserts that this scope is still the thread's top scope before clearing the ThreadLocal. If the ThreadLocal top is a different scope, scopes were closed out of order: some inner scope was left open (or another outer scope was pushed) so the stack is unbalanced, and IllegalStateException reports the actual top. This typically surfaces when try-with-resources blocks are reordered or a scope leaks.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/Assembler.java:252
private int finalCodeSize = -1;
/**
* Returns the final code size after code emission has been completed.
*/
public int finalCodeSize() {
assert codeBuffer.data == null : "Buffer is expected to be closed";
return finalCodeSize;
}
public byte[] copy(int start, int end) {
return codeBuffer.copyData(start, end);
}
private void checkAndClearLabelsWithPatches() throws InternalError {
Label label = labelsWithPatches;
while (label != null) {
if (label.patchPositions != null) {
throw new GraalError("Label used by instructions at following offsets has not been bound: %s", label.patchPositions);
}
Label next = label.nextWithPatches;
label.nextWithPatches = null;
label = next;
}
labelsWithPatches = null;
}
public void bind(Label l) {
assert !l.isBound() : "can bind label only once";
l.bind(position(), this);
}
public abstract void align(int modulus);
/**
* Emit an instruction that will fail in some way if it is reached.
*/View on GitHub (pinned to a66e9ccd1d)
Solutions
- Always create JNIMethodScope with try-with-resources so nesting and closing order match lexically, even on exception paths.
- Find the leaked inner scope named in the message (scopeName is included in toString output via JNIUtil traces) and ensure it is closed before the outer one.
- Avoid storing scopes in fields/collections; keep their lifetime strictly lexical.
Example fix
// before
JNIMethodScope inner = new JNIMethodScope("inner", env);
try (JNIMethodScope outer = new JNIMethodScope("outer", env)) {
...
} // throws: inner still open, topScope != outer
inner.close();
// after
try (JNIMethodScope outer = new JNIMethodScope("outer", env)) {
try (JNIMethodScope inner = new JNIMethodScope("inner", env)) {
...
} // inner closes first
} // outer closes cleanly Defensive patterns
Strategy: validation
Prevention
- Create every JNIMethodScope with try-with-resources so close order always mirrors creation order.
- Enable JNIUtil tracing (level 1) during development to see enter/exit pairs and spot unbalanced scopes early.
- Never store scopes in fields or collections; keep their lifetime lexical.
When it happens
Trigger: Closing the outer scope while an inner scope is still open (e.g. inner scope stored and closed later, or exception paths that skip an inner close()); manually constructing scopes and closing them in the wrong order; nested scopes where the inner one was created on a different control-flow branch and never closed.
Common situations: Breaking out of nested try-with-resources via exceptions that suppress close; refactors that move scope creation out of lexical order; caching scopes in fields so lifetime no longer matches nesting.
Related errors
- Could not parse bytes for type annotations
- The VM does not expose the required Graal capability %s.
- 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/1e4dc3b14de019f6.
Report an issue: GitHub.