{"record":{"id":"99a84085399d48b1","repo":"quarkusio/quarkus","slug":"object-of-class-object-getclass-getname-has-99a840","errorCode":null,"errorMessage":"Object of class ${object.getClass().getName()} has non-deterministic hash code, it cannot be passed as a HashMap key through the recorder boundary: ${object}","messagePattern":"Object of class (.+?) has non-deterministic hash code, it cannot be passed as a HashMap key through the recorder boundary: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java","lineNumber":1153,"sourceCode":"        //we need to create all these first, to ensure the required objects have already\n        //been deserialized\n        List<SerializationStep> setupSteps = new ArrayList<>();\n        List<SerializationStep> ctorSetupSteps = new ArrayList<>();\n\n        if (REPRODUCIBILITY_CHECK) {\n            try {\n                if (param instanceof Set<?> set && set.getClass() == HashSet.class) {\n                    for (Object object : set) {\n                        if (object.getClass().getMethod(\"hashCode\").getDeclaringClass() == Object.class) {\n                            throw new IllegalArgumentException(\"Object of class \" + object.getClass().getName()\n                                    + \" has non-deterministic hash code, it cannot be passed\"\n                                    + \" in a HashSet through the recorder boundary: \" + object);\n                        }\n                    }\n                } else if (param instanceof Map<?, ?> map && map.getClass() == HashMap.class) {\n                    for (Object object : map.keySet()) {\n                        if (object.getClass().getMethod(\"hashCode\").getDeclaringClass() == Object.class) {\n                            throw new IllegalArgumentException(\"Object of class \" + object.getClass().getName()\n                                    + \" has non-deterministic hash code, it cannot be passed\"\n                                    + \" as a HashMap key through the recorder boundary: \" + object);\n                        }\n                    }\n                }\n            } catch (NoSuchMethodException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        boolean relaxedOk = false;\n        if (param instanceof Collection) {\n            //if this is a collection we want to serialize every element\n            for (Object i : (Collection) param) {\n                DeferredParameter val = i != null\n                        ? loadObjectInstance(i, existing, i.getClass(), relaxedValidation)\n                        : loadObjectInstance(null, existing, Object.class, relaxedValidation);\n                setupSteps.add(new SerializationStep() {","sourceCodeStart":1135,"sourceCodeEnd":1171,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java#L1135-L1171","documentation":"The HashMap counterpart of the HashSet check: when recording a HashMap through the recorder boundary, Quarkus verifies each key overrides hashCode(). Keys inheriting Object.hashCode() have nondeterministic iteration/lookup ordering across JVM runs, which would break reproducible builds, so the build fails with this IllegalArgumentException.","triggerScenarios":"Passing a plain HashMap through a recorder method where a key class does not override hashCode(), with the reproducibility check active.","commonSituations":"Recording maps whose keys are custom classes or anonymous/reflection-created objects without hashCode overrides; CI reproducibility checks failing after adding a new recorded map; maps keyed by build-time-generated objects.","solutions":["Override hashCode() and equals() on the key class to be content-based","Use a LinkedHashMap or TreeMap (with a deterministic comparator) instead of HashMap for recorded maps","Normalize keys to Strings or other well-known hashable types before recording","Switch to a List of key/value pairs if key-based lookup isn't needed at runtime","As a last resort disable the reproducibility check, accepting non-reproducible builds"],"exampleFix":"// before\nMap<Key, String> m = new HashMap<>(); // Key uses identity hashCode\nrecorder.setMap(m);\n// after\nclass Key { String id; @Override public int hashCode() { return id.hashCode(); } @Override public boolean equals(Object o) { return o instanceof Key k && k.id.equals(id); } }\nrecorder.setMap(m);","handlingStrategy":"type-guard","validationCode":"static boolean hasDeterministicKeyHash(Map<?, ?> m) throws NoSuchMethodException {\n    for (Object k : m.keySet()) {\n        if (k.getClass().getMethod(\"hashCode\").getDeclaringClass() == Object.class) return false;\n    }\n    return true;\n}","typeGuard":"static boolean overridesHashCode(Class<?> c) throws NoSuchMethodException {\n    return c.getMethod(\"hashCode\").getDeclaringClass() != Object.class;\n}","tryCatchPattern":"try {\n    recorder.setMap(map);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"non-deterministic hash code\")) {\n        recorder.setMap(new LinkedHashMap<>(map)); // preserves insertion order\n    } else { throw e; }\n}","preventionTips":["Override hashCode/equals on map key classes recorded via recorders","Prefer LinkedHashMap or TreeMap with a stable comparator for recorded maps","Key recorded maps by Strings or primitives when possible","Run reproducibility verification in CI to catch identity-hash keys"],"tags":["quarkus","reproducible-build","hashcode","hashmap","determinism"],"backgroundTag":"non-deterministic-hashcode","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}