flowable/flowable-engine · error · IllegalArgumentException

Invalid JSON expression to parse

Error message

Invalid JSON expression to parse

What it means

JsonDataObject.setValue accepts either a JSON-formatted String, a Jackson JsonNode, or an arbitrary bean (serialized via Jackson). If a String is provided and Jackson cannot parse it as JSON, the method wraps the JacksonException in IllegalArgumentException with this message.

Solutions

  1. Ensure the string is valid JSON before calling setValue (e.g. validate with JsonMapper.readTree in a try/catch)
  2. Pass a JsonNode instead of a raw String
  3. Pass a Java bean and let Flowable serialize it, instead of a pre-formatted string

Example fix

// before
dataObject.setValue("{name: 'x'}"); // invalid JSON
// after
dataObject.setValue("{\"name\":\"x\"}");
Defensive patterns

Strategy: try-catch

Try / catch

try { dataObject.setValue(v); } catch (IllegalArgumentException e) { /* v was not valid JSON */ }

Prevention

When it happens

Trigger: Calling jsonDataObject.setValue(someString) where someString is not valid JSON (e.g. plain text, malformed JSON like "{a:1}" with unquoted keys).

Common situations: Passing user input or configuration strings directly as JSON data object values; missing quotes/brackets; JSON5 or trailing commas not supported by Jackson.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-bpmn-model/src/main/java/org/flowable/bpmn/model/JsonDataObject.java:34

import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;

import tools.jackson.core.JacksonException;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.json.JsonMapper;

/**
 * @author Christophe DENEUX
 */
public class JsonDataObject extends ValuedDataObject {

    @Override
    public void setValue(Object value) {
    	if (value instanceof String && !StringUtils.isEmpty(((String) value).trim())) {
            try {
                this.value = JsonMapper.shared().readTree((String) value);
            } catch (JacksonException e) {
                throw new IllegalArgumentException("Invalid JSON expression to parse", e);
            }
        } else if (value instanceof JsonNode) {
    		this.value = value;
        } else {
            JsonMapper mapper = JsonMapper.builder()
                    // By default, Jackson serializes only public fields, we force to use all fields of the Java Bean
                    .changeDefaultVisibility(visibilityChecker -> visibilityChecker.withFieldVisibility(Visibility.ANY))
                    .build();

            this.value = mapper.convertValue(value, JsonNode.class);
    	}
    }

    @Override
    public JsonDataObject clone() {
        JsonDataObject clone = new JsonDataObject();
        clone.setValues(this);
        return clone;

View on GitHub (pinned to d6d39ce1c6)