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
- Use IdentityHashCodes.trySet(o, h) (returns false instead of throwing) when a pre-initialized hashcode is tolerable.
- Guard with IdentityHashCodes.has(o) before calling set.
- Call set() as early as possible on freshly allocated objects, before anything can hash them.
- 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
- Prefer trySet(o, hash) and treat false as 'already initialized, skip'.
- Restore identity hashcodes before the object is inserted into any HashMap/HashSet or logged with hashCode.
- Never hash a freshly deserialized object before running the hashcode-restoration pass.
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
- Missing this in serialized frame.
- Failed to deserialize frame for %s.%s().
- Erroneous deserialization of SuspendCapability.\nread object
- You can't resume a continuation while it is being serialized
- You cannot serialize a continuation whilst it's running, as
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/c9f92d4fd81d2f34.
Report an issue: GitHub.