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

  1. Always create JNIMethodScope with try-with-resources so nesting and closing order match lexically, even on exception paths.
  2. 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.
  3. 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

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


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/1e4dc3b14de019f6. Report an issue: GitHub.