oracle/graal · error · IllegalStateException

Setting ihashcode of an object whose ihashcode is already in

Error message

Setting ihashcode of an object whose ihashcode is already initialized.

What it means

IllegalStateException from IdentityHashCodes.set: the object's identity hashcode was already initialized, so it cannot be reassigned. An identity hashcode gets initialized by Object.hashCode resolving to Object.hashCode, by System.identityHashCode(o), or by a previous successful set/trySet — after that the value is fixed for the object's lifetime, which is exactly why set() refuses to overwrite it. This API exists so continuation deserialization can restore recorded identity hashcodes; overwriting would break hash-table invariants.

Source

Thrown at espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/IdentityHashCodes.java:95

     */
    public static boolean trySet(Object o, int hashcode) {
        checkIsSupported();
        return setIHashcode0(o, hashcode);
    }

    /**
     * Sets the identity hashcode of the given object if it is not already initialized, and throws
     * {@link IllegalStateException} otherwise.
     *
     * @throws UnsupportedOperationException If this VM does not support continuations.
     * @throws NullPointerException if {@code o} is {@code null}.
     * @throws IllegalArgumentException if {@code hashcode <= 0}.
     * @throws IllegalStateException if the identity hashcode of the given object is already
     *             initialized.
     */
    public static void set(Object o, int hashcode) {
        if (!trySet(o, hashcode)) {
            throw new IllegalStateException("Setting ihashcode of an object whose ihashcode is already initialized.");
        }
    }

    private static void checkIsSupported() {
        if (!Continuation.isSupported()) {
            throw new UnsupportedOperationException("This VM does not support identity hashcode preservation.");
        }
    }

    private static native boolean isInitialized0(Object o);

    private static native boolean setIHashcode0(Object o, int hashcode);

    private IdentityHashCodes() {
    }
}

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Use IdentityHashCodes.trySet(o, h) (returns false instead of throwing) when a pre-initialized hashcode is tolerable.
  2. Guard with IdentityHashCodes.has(o) before calling set.
  3. Call set() as early as possible on freshly allocated objects, before anything can hash them.
  4. If the original hashcode matters for correctness (objects live in hash structures keyed by identity), redo the restoration pass before inserting into any HashMap/HashSet.

Example fix

// before
map.put(o, k);            // initializes identity hashcode
IdentityHashCodes.set(o, recordedHash); // throws IllegalStateException

// after
if (!IdentityHashCodes.has(o)) {
    IdentityHashCodes.trySet(o, recordedHash);
}
map.put(o, k); // hash after restore
Defensive patterns

Strategy: validation

Validate before calling

// before set: check initialization state (requires continuation-capable VM)
if (Continuation.isSupported() && !IdentityHashCodes.has(o)) {
    IdentityHashCodes.set(o, recordedHash);
}

Try / catch

try { IdentityHashCodes.set(o, hash); } catch (IllegalStateException e) { /* hashcode already fixed; accept existing value or fail restoration */ }

Prevention

When it happens

Trigger: Calling IdentityHashCodes.set(o, h) after o.hashCode() or System.identityHashCode(o) was already called on the object, or after a prior set/trySet on it; typical during deserialization when framework code hashes the object before restoring its hashcode.

Common situations: A deserializer that puts freshly allocated objects into a HashMap (initializing their identity hashcodes) before calling set; logging or caching code touching hashCode during reconstruction; restoring the same object graph twice.

Related errors


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