flowable/flowable-engine · error · FlowableIllegalArgumentException

Converter can only convert tools.jackson.databind.JsonNode.

Error message

Converter can only convert tools.jackson.databind.JsonNode.

What it means

JsonObjectRestVariableConverter.convertVariableValue only accepts tools.jackson.databind.JsonNode (Jackson 3) values when writing an engine variable to an EngineRestVariable. Any other non-null object type fails the instanceof guard and throws FlowableIllegalArgumentException, since this converter deliberately targets the new tools.jackson API.

Source

Thrown at modules/flowable-common-rest/src/main/java/org/flowable/common/rest/variable/JsonObjectRestVariableConverter.java:61

    public Object getVariableValue(EngineRestVariable result) {
        if (result.getValue() != null) {
            if (result.getValue() instanceof Map || result.getValue() instanceof List) {
                // When the variable is coming from the REST API it automatically gets converted to an ArrayList or
                // LinkedHashMap. In all other cases JSON is saved as ArrayNode or ObjectNode. For consistency the
                // variable is converted to such an object here.
                return objectMapper.valueToTree(result.getValue());
            } else {
                return result.getValue();
            }
        }
        return null;
    }

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

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Build the value with tools.jackson JsonMapper/JsonNode so the instanceof check passes.
  2. If you only have a Jackson 2 JsonNode, convert it (e.g. via its toString() parsed by tools.jackson readTree) or use Jackson2JsonObjectRestVariableConverter.
  3. Unify the classpath on a single Jackson generation to avoid cross-API node types.
  4. Parse Strings/Maps into a tools.jackson JsonNode before calling the converter.

Example fix

// before
com.fasterxml.jackson.databind.JsonNode oldNode = oldMapper.valueToTree(map);
converter.convertVariableValue(oldNode, restVar); // throws

// after
tools.jackson.databind.JsonNode node = toolsJacksonMapper.valueToTree(map);
converter.convertVariableValue(node, restVar);
Defensive patterns

Strategy: type-guard

Validate before calling

if (value instanceof tools.jackson.databind.JsonNode node) {
    converter.convertVariableValue(node, restVar);
} else {
    converter.convertVariableValue(toolsJacksonMapper.valueToTree(value), restVar);
}

Type guard

static boolean isJackson3JsonNode(Object v) {
    return v instanceof tools.jackson.databind.JsonNode;
}

Try / catch

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

Prevention

When it happens

Trigger: Passing a non-null object that is not a tools.jackson.databind.JsonNode (e.g. a com.fasterxml.jackson.databind.JsonNode from Jackson 2, a String, or a Map) into convertVariableValue, typically during REST variable serialization.

Common situations: Jackson 2 to Jackson 3 migration where callers still construct nodes with the old com.fasterxml API; mixing both Jacksons on the classpath; passing pre-serialized JSON strings instead of parsed nodes.

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/d47b47b241a5553f. Report an issue: GitHub.