flowable/flowable-engine · error · FlowableIllegalArgumentException

Converter can only convert com.fasterxml.jackson.databind.Js

Error message

Converter can only convert com.fasterxml.jackson.databind.JsonNode.

What it means

Jackson2JsonObjectRestVariableConverter.convertVariableValue only accepts com.fasterxml.jackson.databind.JsonNode values when serializing an engine variable to a REST variable. If the supplied object is any other type, it throws FlowableIllegalArgumentException because the converter's contract is exclusively JsonNode-to-REST. Note the snippet then calls tools.jackson readTree, indicating a Jackson 2/3 migration inconsistency: the instanceof check guards the Jackson 2 type while downstream code targets tools.jackson (Jackson 3).

Source

Thrown at modules/flowable-common-rest/src/main/java/org/flowable/common/rest/variable/Jackson2JsonObjectRestVariableConverter.java:55

    public String getRestTypeName() {
        return "json";
    }

    @Override
    public Class<?> getVariableType() {
        return JsonNode.class;
    }

    @Override
    public Object getVariableValue(EngineRestVariable result) {
        throw new UnsupportedOperationException("Cannot get variable value for jackson 2");
    }

    @Override
    public void convertVariableValue(Object variableValue, EngineRestVariable result) {
        if (variableValue != null) {
            if (!(variableValue instanceof JsonNode)) {
                throw new FlowableIllegalArgumentException("Converter can only convert com.fasterxml.jackson.databind.JsonNode.");
            }
            tools.jackson.databind.JsonNode valueNode = objectMapper.readTree(variableValue.toString());
            result.setValue(valueNode);
        } else {
            result.setValue(null);
        }
    }

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Ensure the variable value passed in is a com.fasterxml.jackson.databind.JsonNode built with the same ObjectMapper instance the converter uses.
  2. If migrating to tools.jackson (Jackson 3), use JsonObjectRestVariableConverter instead, or update the instanceof check and imports to the same Jackson flavor used downstream.
  3. Remove duplicate/old Jackson versions from the classpath so both the converter and callers agree on one Jackson.
  4. If the value is a String or Map, parse it first (objectMapper.readTree / valueToTree) before handing it to the converter.

Example fix

// before
EngineRestVariable restVar = new EngineRestVariable();
converter.convertVariableValue("{\"a\":1}", restVar);

// after
JsonNode node = objectMapper.readTree("{\"a\":1}"); // com.fasterxml.jackson.databind.JsonNode
converter.convertVariableValue(node, restVar);
Defensive patterns

Strategy: type-guard

Validate before calling

if (value instanceof com.fasterxml.jackson.databind.JsonNode node) {
    converter.convertVariableValue(node, restVar);
} else if (value != null) {
    converter.convertVariableValue(objectMapper.readTree(value.toString()), restVar);
}

Type guard

static boolean isJackson2JsonNode(Object v) {
    return v instanceof com.fasterxml.jackson.databind.JsonNode;
}

Try / catch

try {
    converter.convertVariableValue(value, restVar);
} catch (FlowableIllegalArgumentException e) {
    throw new IllegalArgumentException("Expected a Jackson 2 JsonNode variable value, got: "
        + (value == null ? "null" : value.getClass().getName()), e);
}

Prevention

When it happens

Trigger: Calling convertVariableValue(variableValue, result) with a non-null object that is not a com.fasterxml.jackson.databind.JsonNode (e.g. a String, Map, ObjectNode from tools.jackson, or a POJO), typically via REST variable serialization when the variable's Java type was resolved to this converter.

Common situations: Mixed Jackson versions on the classpath during a Jackson 2 to Jackson 3 (tools.jackson) migration: code builds an ObjectNode with one Jackson but the converter checks the other. Also passing raw JSON strings or Maps instead of a parsed JsonNode.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/87705957e3798ccb. Report an issue: GitHub.