flowable/flowable-engine · error · FlowableException

Invalid body was supplied

Error message

Invalid body was supplied

What it means

Flowable's REST endpoint for updating a process-instance variable requires a JSON body deserializable into a RestVariable object. After parsing, if the deserialized object is null (i.e. an empty body or a JSON literal 'null'), the endpoint throws FlowableException("Invalid body was supplied"). This guards downstream logic that expects a non-null variable payload.

Solutions

  1. Send a valid JSON RestVariable body, e.g. {"name":"<variableName>","type":"string","value":"myValue"}.
  2. Ensure the variable name in the body matches the {variableName} URL segment.
  3. Verify the client sets Content-Type: application/json and actually transmits the body (check curl -v output or proxy logs).
  4. If using a reverse proxy, confirm it does not drop request bodies on PUT.

Example fix

// before
curl -X PUT -H 'Content-Type: application/json' \
  http://host/flowable-rest/runtime/process-instances/123/variables/orderId

// after
curl -X PUT -H 'Content-Type: application/json' \
  -d '{"name":"orderId","type":"string","value":"ABC-1"}' \
  http://host/flowable-rest/runtime/process-instances/123/variables/orderId
Defensive patterns

Strategy: validation

Validate before calling

const body = { name: variableName, type: 'string', value: 'x' };
if (!body || !body.name) throw new Error('RestVariable body required');
await fetch(url, { method: 'PUT', headers: {'Content-Type':'application/json'}, body: JSON.stringify(body) });

Type guard

function isValidRestVariable(v) {
  return v != null && typeof v.name === 'string' && v.name.length > 0 && 'value' in v;
}

Try / catch

try {
  const res = await api.put(`/process-instances/${id}/variables/${name}`, body);
} catch (e) {
  if (e.response && /Invalid body was supplied/.test(e.response.data && e.response.data.message || '')) {
    // rebuild and retry with a proper RestVariable body
  }
}

Prevention

When it happens

Trigger: PUT/POST to /runtime/process-instances/{processInstanceId}/variables/{variableName} with an empty request body, a body of literal 'null', or a body whose content is dropped before it reaches objectMapper.readValue(request.getInputStream(), RestVariable.class).

Common situations: Clients sending PUT without a body (e.g. curl -X PUT without -d), proxies/gateways stripping bodies, Content-Type header set but payload omitted, or test scripts calling the endpoint with no data.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableResource.java:117

        RestVariable result = null;
        if (request instanceof MultipartHttpServletRequest) {
            result = setBinaryVariable((MultipartHttpServletRequest) request, execution, false, false);

            if (!result.getName().equals(variableName)) {
                throw new FlowableIllegalArgumentException("Variable name in the body should be equal to the name used in the requested URL.");
            }

        } else {
            RestVariable restVariable = null;
            try {
                restVariable = objectMapper.readValue(request.getInputStream(), RestVariable.class);
            } catch (Exception e) {
                throw new FlowableIllegalArgumentException("request body could not be transformed to a RestVariable instance.", e);
            }

            if (restVariable == null) {
                throw new FlowableException("Invalid body was supplied");
            }
            if (!restVariable.getName().equals(variableName)) {
                throw new FlowableIllegalArgumentException("Variable name in the body should be equal to the name used in the requested URL.");
            }

            result = setSimpleVariable(restVariable, execution, false, false);
        }
        return result;
    }
    
    @ApiOperation(value = "Update a single variable on a process instance asynchronously", tags = { "Process Instance Variables" }, nickname = "updateProcessInstanceVariableAsync",
            notes = "This endpoint can be used in 2 ways: By passing a JSON Body (RestVariable) or by passing a multipart/form-data Object.\n"
                    + "Note that scope is ignored, only local variables can be set in a process instance.\n"
                    + "NB: Swagger V2 specification does not support this use case that is why this endpoint might be buggy/incomplete if used with other tools.")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "body", type = "org.flowable.rest.service.api.engine.variable.RestVariable", value = "Create a variable on a process instance", paramType = "body", example = "{\n" +
                    "    \"name\":\"intProcVar\"\n" +
                    "    \"type\":\"integer\"\n" +

View on GitHub (pinned to d6d39ce1c6)