flowable/flowable-engine · error · FlowableException

Invalid body was supplied

Error message

Invalid body was supplied

What it means

After successfully parsing the request body into a RestVariable, the update-variable endpoint checks that the resulting object is non-null. FlowableException('Invalid body was supplied') is thrown if Jackson parsed the stream but produced a null RestVariable (e.g. body was the literal JSON 'null' or effectively empty). It guards downstream code from dereferencing a null variable.

Solutions

  1. Send a complete JSON object with at least name, type and value fields.
  2. Verify client-side serialization is not producing the string 'null'.
  3. Add a client-side check that the payload object exists before issuing the PUT.

Example fix

// before
curl -X PUT -H 'Content-Type: application/json' .../tasks/123/variables/name -d 'null'

// after
curl -X PUT -H 'Content-Type: application/json' .../tasks/123/variables/name -d '{"name":"name","type":"string","value":"John"}'
Defensive patterns

Strategy: type-guard

Validate before calling

if (payload == null || payload.name == null || payload.value === undefined) {
  throw new Error('refusing to PUT null/empty variable body');
}

Type guard

function isValidBody(v) {
  return v != null && typeof v === 'object' && typeof v.name === 'string';
}

Try / catch

try {
  return await putVariable(url, body);
} catch (e) {
  if (String(e.message).includes('Invalid body was supplied')) console.error('body serialized to null:', body);
  throw e;
}

Prevention

When it happens

Trigger: PUT /runtime/tasks/{taskId}/variables/{variableName} (non-multipart) with a body that deserializes to null, most commonly the literal body 'null', or an empty/whitespace stream that Jackson maps to null.

Common situations: Client sends 'null' as body; template/serialization bug where variable payload is null; empty body with Content-Type: application/json passing the Jackson parse without exception.

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

Appendix: source

Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableResource.java:121

        if (request instanceof MultipartHttpServletRequest) {
            result = setBinaryVariable((MultipartHttpServletRequest) request, task, 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("Error converting request body to 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, task, false);
        }
        return result;
    }

    @ApiOperation(value = "Delete a variable on a task", tags = { "Task Variables" }, nickname = "deleteTaskInstanceVariable", code = 204)
    @ApiImplicitParams(@ApiImplicitParam(name = "scope", dataType = "string", value = "Scope of variable to be returned. When local, only task-local variable value is returned. When global, only variable value from the task’s parent execution-hierarchy are returned. When the parameter is omitted, a local variable will be returned if it exists, otherwise a global variable.", paramType = "query"))
    @ApiResponses(value = {
            @ApiResponse(code = 204, message = "Indicates the task variable was found and has been deleted. Response-body is intentionally empty."),
            @ApiResponse(code = 404, message = "Indicates the requested task was not found or the task does not have a variable with the given name. Status message contains additional information about the error.")
    })
    @DeleteMapping(value = "/runtime/tasks/{taskId}/variables/{variableName}")
    @ResponseStatus(HttpStatus.NO_CONTENT)

View on GitHub (pinned to d6d39ce1c6)