FasterXML/jackson-databind · error · UnsupportedOperationException

Cannot call withValueDeserializer() on ${getClass().getName(

Error message

Cannot call withValueDeserializer() on ${getClass().getName()}

What it means

The ObjectNode-backed SettableAnyProperty variant (used when deserializing directly into a tree ObjectNode) throws on withValueDeserializer() because the value deserializer is fixed by the node factory and cannot be swapped. Calling this mutant factory on the tree variant is a programming error.

Source

Thrown at src/main/java/tools/jackson/databind/deser/SettableAnyProperty.java:526

        // Let's override since this is much simpler with JsonNodes
        @Override
        public Object deserialize(JsonParser p, DeserializationContext ctxt)
            throws JacksonException
        {
            return _valueDeserializer.deserialize(p, ctxt);
        }

        @Override
        protected void _set(DeserializationContext ctxt, Object instance, Object propName, Object value)
            throws Exception
        {
            ((ObjectNode) instance).set((String) propName, (JsonNode) value);
        }

        // Should not get called but...
        @Override
        public SettableAnyProperty withValueDeserializer(ValueDeserializer<Object> deser) {
            throw new UnsupportedOperationException("Cannot call withValueDeserializer() on " + getClass().getName());
        }

        @Override
        public int getParameterIndex() { return _parameterIndex; }

        @Override
        public Object createParameterObject() { return _nodeFactory.objectNode(); }
    }
}

View on GitHub (pinned to 87876ca5c0)

Solutions

  1. Guard any generic withValueDeserializer() call with an instanceof check to skip the node-backed any-setter variant.
  2. Use a custom deserializer for the node content itself rather than trying to rewire the any-setter.
  3. Avoid mixing ObjectNode target deserialization with code that assumes POJO any-setter semantics.

Example fix

// before
for (SettableBeanProperty p : props) {
    prop = p.withValueDeserializer(wrapped); // throws on node variant
}

// after
for (SettableBeanProperty p : props) {
    if (!(p instanceof SettableAnyProperty) || p.getClass().getSimpleName().startsWith("Method")) {
        prop = p.withValueDeserializer(wrapped);
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (p.getClass().getName().contains("ObjectNode")
        || p instanceof SettableAnyProperty && p.getParameterIndex() >= 0
            && p.getClass().getEnclosingClass() == ObjectNode.class) {
    // skip; node variant does not accept withValueDeserializer
}

Type guard

static boolean canReplaceDeserializer(SettableBeanProperty p) {
    // the node-backed variant throws; only POJO any-setters accept replacement
    return !(p.getClass().getName().toLowerCase().contains("node"));
}

Try / catch

try { p.withValueDeserializer(wrapped); }
catch (UnsupportedOperationException e) {
    // skip this property; it is the fixed node variant
}

Prevention

When it happens

Trigger: Custom deserializer/framework code calling withValueDeserializer() on the any-setter that targets ObjectNode (the JsonNode any-setter); a generic pipeline that indiscriminately rewraps every SettableBeanProperty with a new deserializer.

Common situations: A framework that wraps all properties with a tracing/auditing deserializer and hits the node variant; mixing tree-model deserialization with POJO binding in the same processing pipeline; subclassing that calls super.withValueDeserializer() on the node variant.

Related errors


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