{"record":{"id":"a18310204a69ef2f","repo":"FasterXML/jackson-databind","slug":"trying-to-resolve-a-forward-reference-with-id-i-a18310","errorCode":null,"errorMessage":"Trying to resolve a forward reference with id [${id}] that wasn't previously seen as unresolved.","messagePattern":"Trying to resolve a forward reference with id \\[(.+?)\\] that wasn't previously seen as unresolved\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/tools/jackson/databind/deser/jdk/CollectionDeserializer.java","lineNumber":659,"sourceCode":"        public void resolveForwardReference(DeserializationContext ctxt, Object id, Object value) throws JacksonException\n        {\n            Iterator<CollectionReferring> iterator = _accumulator.iterator();\n            // Resolve ordering after resolution of an id. This mean either:\n            // 1- adding to the result collection in case of the first unresolved id.\n            // 2- merge the content of the resolved id with its previous unresolved id.\n            Collection<Object> previous = _result;\n            while (iterator.hasNext()) {\n                CollectionReferring ref = iterator.next();\n                if (ref.hasId(id)) {\n                    iterator.remove();\n                    previous.add(value);\n                    previous.addAll(ref.next);\n                    return;\n                }\n                previous = ref.next;\n            }\n\n            throw new IllegalArgumentException(\"Trying to resolve a forward reference with id [\" + id\n                    + \"] that wasn't previously seen as unresolved.\");\n        }\n\n        /**\n         * Replace a resolved item in the result collection. Called when the bound\n         * item is rebound (e.g., builder → built object) via\n         * {@link Referring#handleItemRebind}.\n         *\n         * @param oldItem Item to replace (Builder)\n         * @param newItem Item to replace {@code oldItem} with (Built value)\n         *\n         * @since 3.2\n         */\n        public void replaceResolvedItem(Object oldItem, Object newItem) {\n            if (_result instanceof List<?>) {\n                @SuppressWarnings(\"unchecked\")\n                List<Object> list = (List<Object>) _result;\n                for (int i = 0, len = list.size(); i < len; i++) {","sourceCodeStart":641,"sourceCodeEnd":677,"githubUrl":"https://github.com/FasterXML/jackson-databind/blob/87876ca5c0569b4933aec2d30d6225e4b9ba3a43/src/main/java/tools/jackson/databind/deser/jdk/CollectionDeserializer.java#L641-L677","documentation":"Thrown by CollectionDeserializer.CollectionReferringAccumulator.resolveForwardReference when an object identity (from @JsonIdentityInfo) is being resolved against a Collection, but the supplied id was never registered as an unresolved forward reference. Jackson only records ids that it could not immediately satisfy during parsing; resolving any other id is a programmer/input error. It surfaces as an IllegalArgumentException because the accumulator's pending list does not contain the id.","triggerScenarios":"Deserializing JSON with @JsonIdentityInfo on a Collection element type where a \"@ref\" points to an id that was already resolved, never declared, or is a duplicate; or manually calling objectMapper.takeValueAsSomething followed by resolveForwardReferences with a stale/incorrect id on a Collection-typed property.","commonSituations":"Cyclic object graphs serialized with @JsonIdentityInfo where the JSON payload has been hand-edited or generated by a producer that emits duplicate @ref entries; round-tripping data through a cache that strips the first occurrence of an object; upgrading from a version that silently ignored unknown refs to one that enforces them.","solutions":["Inspect the JSON for the @ref whose id does not match any earlier @id in the same Collection, and correct the producer.","If you call resolveForwardReferences manually, ensure you only resolve ids returned by UnresolvedForwardReference iterators from the same deserialization pass.","Disable @JsonIdentityInfo on the element type (or scope it to a property) if forward references are not required, switching to default inline serialization.","Add a custom DeserializationProblemHandler to log the offending id and continue instead of aborting."],"exampleFix":"// before\n@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property=\"@id\")\npublic class Node { public List<Node> children; }\n// JSON has {\"@ref\":42} but no prior {\"@id\":42}\n\n// after: validate ids before resolving, or drop identity info\nList<Node> nodes = mapper.readValue(json, new TypeReference<List<Node>>(){});\n// ensure every @ref in the payload has a matching earlier @id","handlingStrategy":"validation","validationCode":"// Before resolving, confirm the id is actually pending.\nUnresolvedForwardReference ufr = ...;\nObject idToResolve = ...;\nboolean known = false;\nfor (ReadableObjectId roid : ufr) { if (roid.hasId(idToResolve)) { known = true; break; } }\nif (!known) { log.warn(\"Unknown forward-ref id {} ignored\", idToResolve); }\nelse { roid.tryResolve(...); }","typeGuard":null,"tryCatchPattern":"try {\n    mapper.readerFor(Node.class).withAttribute(...).readValue(json);\n} catch (UnresolvedForwardReference e) {\n    // do NOT blindly iterate; only resolve ids reported by e\n    Iterator<ReadableObjectId> it = e.iterator();\n    while (it.hasNext()) { ReadableObjectId r = it.next(); /* handle */ }\n}","preventionTips":["Validate @JsonIdentityInfo payloads end-to-end on the producer side so every @ref has a prior @id.","Never call resolveForwardReferences with ids obtained from sources other than the current UnresolvedForwardReference.","Run a schema/round-trip test that re-serializes parsed output and diffs ids to catch duplicate refs early."],"tags":["deserialization","json-identity","collections","forward-reference","illegal-argument"],"backgroundTag":null,"analyzedSha":"87876ca5c0569b4933aec2d30d6225e4b9ba3a43","analyzedAt":"2026-08-11T12:55:24.033Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}