flowable/flowable-engine · error · FlowableIllegalArgumentException
Error converting request body to RestVariable instance
Error message
Error converting request body to RestVariable instance
What it means
For non-multipart PUT requests to update a task variable, Flowable deserializes the request body JSON into a RestVariable object with Jackson's ObjectMapper. FlowableIllegalArgumentException is thrown when the body cannot be parsed/converted (malformed JSON, wrong shape, encoding problems). The original exception is preserved as the cause.
Solutions
- Send a valid JSON body shaped like RestVariable: {"name":"var","type":"string","value":"x"}.
- Set header Content-Type: application/json on the request.
- Validate the JSON with a linter or by deserializing client-side before sending.
- Check the exception cause in server logs for the exact Jackson parse error.
Example fix
// before (form-encoded, not JSON)
curl -X PUT .../tasks/123/variables/name -d 'value=John'
// after
curl -X PUT -H 'Content-Type: application/json' .../tasks/123/variables/name -d '{"name":"name","type":"string","value":"John"}' Defensive patterns
Strategy: validation
Validate before calling
function buildVariablePayload(name, type, value) {
const payload = JSON.stringify({ name, type, value });
JSON.parse(payload); // throws early if serialization produced invalid JSON
return payload;
} Type guard
function isRestVariable(obj) {
return typeof obj === 'object' && obj !== null &&
typeof obj.name === 'string' &&
('value' in obj) && typeof obj.type === 'string';
} Try / catch
try {
const resp = await fetch(url, { method: 'PUT', headers: {'Content-Type': 'application/json'}, body });
if (!resp.ok) throw new Error(await resp.text());
} catch (e) {
if (String(e.message).includes('Error converting request body')) console.error('body was not valid RestVariable JSON:', body);
throw e;
} Prevention
- Always send Content-Type: application/json for non-multipart variable updates.
- Validate the JSON body against the RestVariable shape client-side before sending.
- Never send form-encoded or XML bodies to the variable update endpoint.
- Test payloads with a JSON linter in CI for API client code.
When it happens
Trigger: PUT /runtime/tasks/{taskId}/variables/{variableName} with a Content-Type other than multipart whose input stream is not valid JSON for RestVariable: malformed JSON, missing quotes, wrong content type (e.g. form-encoded), empty body, or JSON with incompatible fields.
Common situations: Sending form-urlencoded data instead of JSON; forgetting Content-Type: application/json; trailing commas or syntax errors; sending XML; empty PUT body.
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
- A request body was expected when executing the form submit.
- Attachment name is required.
- Failed to serialize to a AttachmentRequest instance
- Failed to serialize to a RestVariable instance
- Id cannot be null.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/3b89a7e143ecdcf4.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableResource.java:117
Task task = getTaskFromRequestWithoutAccessCheck(taskId);
RestVariable result = null;
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."),View on GitHub (pinned to d6d39ce1c6)