flowable/flowable-engine · error · FlowableIllegalArgumentException

request body could not be transformed to a RestVariable inst

Error message

request body could not be transformed to a RestVariable instance.

What it means

Thrown by updateVariable when the request body cannot be deserialized into a RestVariable object by Jackson (objectMapper.readValue). Flowable wraps the underlying parse exception in a FlowableIllegalArgumentException, indicating the client sent a malformed or non-JSON body.

Source

Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceVariableResource.java:108

            HttpServletRequest request) {

        CaseInstance caseInstance = getCaseInstanceFromRequestWithoutAccessCheck(caseInstanceId);

        RestVariable result = null;
        if (request instanceof MultipartHttpServletRequest) {
            result = setBinaryVariable((MultipartHttpServletRequest) request, caseInstance.getId(), CmmnRestResponseFactory.VARIABLE_CASE, false,
                    false, RestVariable.RestVariableScope.GLOBAL, createVariableInterceptor(caseInstance));

            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, caseInstance.getId(), false, false, RestVariable.RestVariableScope.GLOBAL, CmmnRestResponseFactory.VARIABLE_CASE, createVariableInterceptor(caseInstance));
        }
        return result;
    }
    
    @ApiOperation(value = "Update a single variable on a case instance asynchronously", tags = { "Case Instance Variables" }, nickname = "updateCaseInstanceVariableAsync",
            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 global variables can be set in a case instance.\n"
                    + "NB: Swagger V2 specification doesn't support this use case that is why this endpoint might be buggy/incomplete if used with other tools.")

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Send a valid JSON RestVariable object with Content-Type: application/json, e.g. {"name":"x","value":5,"type":"integer"}.
  2. Validate the body parses as JSON before sending (e.g. JSON.parse in client code).
  3. Ensure no proxy/gateway is truncating or transforming the request body.
  4. If sending binary content, use the multipart form endpoint instead of the JSON body path.

Example fix

// before: invalid body
curl -X PUT .../variables/count -d 'count=5'
// after: proper RestVariable JSON
curl -X PUT .../variables/count -H 'Content-Type: application/json' -d '{"name":"count","value":5,"type":"integer"}'
Defensive patterns

Strategy: validation

Validate before calling

const bodyJson = JSON.stringify({ name: variableName, value: value, type: typeof value === 'number' ? 'integer' : 'string' });
JSON.parse(bodyJson); // fail fast client-side if not valid JSON
// ensure header: 'Content-Type: application/json'

Type guard

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

Try / catch

try {
  await updateCaseVariable(caseId, name, restVariable);
} catch (e) {
  if (e.status === 400) { /* body wasn't a RestVariable: re-serialize and retry once */ }
  else throw e;
}

Prevention

When it happens

Trigger: PUT /cmmn-runtime/case-instances/{id}/variables/{name} with a non-multipart request whose body is not valid JSON, is empty, has wrong Content-Type (e.g. form-encoded or missing application/json), or whose JSON structure doesn't map to RestVariable.

Common situations: Forgetting to set Content-Type: application/json; sending raw values (e.g. just '5') instead of a RestVariable JSON object; truncated bodies from proxies; clients sending XML or URL-encoded form data.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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