FasterXML/jackson-databind · error · IllegalArgumentException

Invalid Object Id definition for

Error message

Invalid Object Id definition for %s: cannot find property with name %s

What it means

Thrown by BeanDeserializerFactory when @JsonIdentityInfo uses ObjectIdGenerators.PropertyGenerator and the named property cannot be found among the bean's settable properties. With a property-based generator, the id must live in an existing, settable property on the bean; if no property matches the configured name, the Object Id definition is invalid.

Solutions

  1. Ensure a settable property with the configured name exists (field, setter, or creator parameter) on the bean.
  2. Correct the property= value in @JsonIdentityInfo to match an existing property name.
  3. If the type is abstract and has no settable properties, note the factory skips this for abstract types (databind#4014); ensure concrete subtypes define the property.
  4. Switch to a non-property generator (e.g., SequenceGenerator, UUIDGenerator) if you have no natural id property.

Example fix

// before: 'id' property does not exist on the bean
@JsonIdentityInfo(
    generator=ObjectIdGenerators.PropertyGenerator.class,
    property="id")
class Node { String name; }

// after: add the id property
class Node { @JsonProperty("id") Long id; String name; }
Defensive patterns

Strategy: validation

Validate before calling

JsonIdentityInfo ann = type.getAnnotation(JsonIdentityInfo.class);
if (ann != null && ann.generator() == ObjectIdGenerators.PropertyGenerator.class) {
    Set<String> names = beanProperties.stream().map(BeanPropertyDefinition::getName).collect(toSet());
    if (!names.contains(ann.property())) {
        throw new IllegalStateException("@JsonIdentityInfo property '" + ann.property() + "' not found on " + type);
    }
}

Prevention

When it happens

Trigger: Annotating a type with @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id") where no field/setter/creator parameter named 'id' exists on the bean (or it is ignored/not visible).

Common situations: Renaming or removing the id property after adding @JsonIdentityInfo; pointing the property to a getter-only (no setter/field) that is not a creator argument; visibility settings hiding the property; misspelling the property name.

Related errors


AI-assisted analysis of FasterXML/jackson-databind@87876ca5c0 (2026-08-11). Data as JSON: /api/errors/b443e2af3ba3a4bb. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/tools/jackson/databind/deser/BeanDeserializerFactory.java:424

        JavaType idType;
        SettableBeanProperty idProp;
        ObjectIdGenerator<?> gen;

        ObjectIdResolver resolver = ctxt.objectIdResolverInstance(beanDescRef.getClassInfo(), objectIdInfo);

        // Just one special case: Property-based generator is trickier
        if (implClass == ObjectIdGenerators.PropertyGenerator.class) { // most special one, needs extra work
            PropertyName propName = objectIdInfo.getPropertyName();
            idProp = deserBuilder.findProperty(propName);
            if (idProp == null) {
                // [databind#4014]: For abstract types (interfaces, abstract classes),
                // the builder may not have settable properties (no setter/field).
                // Concrete subtype deserializers will set up their own ObjectIdReader,
                // so we can safely skip it here for the abstract type.
                if (beanDescRef.getType().isAbstract()) {
                    return;
                }
                throw new IllegalArgumentException("Invalid Object Id definition for %s: cannot find property with name %s".formatted(
                        ClassUtil.getTypeDescription(beanDescRef.getType()),
                        ClassUtil.name(propName)));
            }
            idType = idProp.getType();
            gen = new PropertyBasedObjectIdGenerator(objectIdInfo.getScope());
        } else {
            JavaType type = ctxt.constructType(implClass);
            idType = ctxt.getTypeFactory().findTypeParameters(type, ObjectIdGenerator.class)[0];
            idProp = null;
            gen = ctxt.objectIdGeneratorInstance(beanDescRef.getClassInfo(), objectIdInfo);
        }
        // also: unlike with value deserializers, let's just resolve one we need here
        ValueDeserializer<?> deser = ctxt.findRootValueDeserializer(idType);
        deserBuilder.setObjectIdReader(ObjectIdReader.construct(idType,
                objectIdInfo.getPropertyName(), gen, deser, idProp, resolver));
    }

    @SuppressWarnings("unchecked")

View on GitHub (pinned to 87876ca5c0)