{"record":{"id":"2798e8bac15af763","repo":"quarkusio/quarkus","slug":"object-of-class-object-getclass-getname-has","errorCode":null,"errorMessage":"Object of class ${object.getClass().getName()} has non-deterministic hash code, it cannot be passed in a HashSet through the recorder boundary: ${object}","messagePattern":"Object of class (.+?) has non-deterministic hash code, it cannot be passed in a HashSet 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":1145,"sourceCode":"     * @param existing The existing object map\n     * @param expectedType The expected type of the object\n     * @param relaxedValidation\n     * @return\n     */\n    private DeferredParameter loadComplexObject(Object param, Map<Object, DeferredParameter> existing,\n            Class<?> expectedType, boolean relaxedValidation) {\n        //a list of steps that are performed on the object after it has been created\n        //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","sourceCodeStart":1127,"sourceCodeEnd":1163,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java#L1127-L1163","documentation":"With the reproducibility check enabled, Quarkus validates HashSet parameters recorded across the recorder boundary. Objects relying on Object.hashCode() (identity hash) produce iteration order that changes between JVM runs, breaking reproducible builds, so they are rejected. The element class must override hashCode().","triggerScenarios":"Passing a plain HashSet through a recorder method where at least one element does not override hashCode() (inherits it from java.lang.Object), while REPRODUCIBILITY_CHECK is on (quarkus.test.record-scan-results / reproducible-build settings).","commonSituations":"Recording sets of internally-defined classes lacking hashCode/equals overrides; storing config-derived sets of arbitrary classes; build reproducibility verification failing in CI after adding a new recorded set.","solutions":["Override hashCode() (and equals()) on the element class so set ordering is deterministic","Use a LinkedHashSet or sorted set (TreeSet with a stable comparator) instead of HashSet for recorded sets","Replace HashSet with a List if order semantics are unimportant but stability is","Disable the reproducibility check only as a last resort (it exists to keep builds byte-for-byte reproducible)","Wrap elements in a type with a content-based hashCode before recording"],"exampleFix":"// before\nclass Entry { String name; } // no hashCode -> identity hash\nrecorder.setEntries(new HashSet<>(entries));\n// after\nclass Entry { String name; @Override public int hashCode() { return name.hashCode(); } }\nrecorder.setEntries(new HashSet<>(entries));","handlingStrategy":"type-guard","validationCode":"static boolean hasDeterministicHash(Collection<?> c) {\n    for (Object o : c) {\n        try {\n            if (o.getClass().getMethod(\"hashCode\").getDeclaringClass() == Object.class) return false;\n        } catch (NoSuchMethodException e) { 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.setEntries(set);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"non-deterministic hash code\")) {\n        recorder.setEntries(new LinkedHashSet<>(set)); // stable iteration order\n    } else { throw e; }\n}","preventionTips":["Always override hashCode/equals on classes recorded inside HashSets","Prefer LinkedHashSet or TreeSet for recorded collections","Enable/keep the reproducibility check in CI to catch these early"],"tags":["quarkus","reproducible-build","hashcode","recorder","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"}