flowable/flowable-engine · error · FlowableContentNotSupportedException

Serialized objects are not allowed

Error message

Serialized objects are not allowed

What it means

Flowable's CMMN REST variable upload rejects request bodies that contain Java-serialized objects. When a binary variable is uploaded via multipart, setBinaryVariable attempts to deserialize the stream with ObjectInputStream; if the part's content type is not application/x-java-serialized-object it refuses to proceed, because deserializing arbitrary bytes is unsafe and unsupported. This guards the REST API against unsafe deserialization of untrusted payloads.

Solutions

  1. Set the multipart part's Content-Type to application/x-java-serialized-object if you really intend to upload a serialized Java object
  2. Upload the data as a plain binary/file part instead and store it via content/attachment endpoints rather than as a serialized variable
  3. Send simple values as JSON variables (typed with the variable type) instead of serializing them client-side
  4. If the class really is missing or the object should not be serialized, restructure the payload as primitives/JSON-serializable types

Example fix

// before: part Content-Type: application/octet-stream, body: <serialized java object bytes>
// after (Java client):
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
HttpHeaders partHeaders = new HttpHeaders();
partHeaders.setContentType(MediaType.parseMediaType("application/x-java-serialized-object"));
HttpEntity<byte[]> part = new HttpEntity<>(serializedBytes, partHeaders);
body.add("data", part);
Defensive patterns

Strategy: validation

Validate before calling

if (!"application/x-java-serialized-object".equals(part.getContentType())) {
    throw new IllegalArgumentException("Part must be application/x-java-serialized-object or use a JSON variable instead");
}

Type guard

boolean isSerializedObjectType(String contentType) {
    return contentType != null && contentType.startsWith("application/x-java-serialized-object");
}

Try / catch

try {
    postBinaryVariable(name, file);
} catch (HttpServerErrorException | HttpClientErrorException e) {
    if (e.getResponseBodyAsString().contains("Serialized objects are not allowed")) {
        // switch to JSON variable or set correct part content type
    }
}

Prevention

When it happens

Trigger: POSTing a binary variable to the CMMN REST variable collection endpoint with a multipart part whose Content-Type is not application/x-java-serialized-object (e.g. application/octet-stream) while the resource expects a serialized object, or sending raw serialized bytes without declaring the java serialized object content type.

Common situations: Clients uploading files with a generic content type, HTTP clients that mislabel multipart parts, migration from older Flowable/Activiti REST APIs that accepted arbitrary binary payloads, security-hardened setups where serialized objects were intentionally disallowed.

Related errors


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

Appendix: source

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

            }

            if (variableScope != null) {
                scope = RestVariable.getScopeFromString(variableScope);
            }

            if (variableType.equals(CmmnRestResponseFactory.BYTE_ARRAY_VARIABLE_TYPE)) {
                // Use raw bytes as variable value
                byte[] variableBytes = IOUtils.toByteArray(file.getInputStream());
                setVariable(instanceId, variableName, variableBytes, scope, isNew, async, variableInterceptor);

            } else if (isSerializableVariableAllowed) {
                // Try deserializing the object
                ObjectInputStream stream = new ObjectInputStream(file.getInputStream());
                Object value = stream.readObject();
                setVariable(instanceId, variableName, value, scope, isNew, async, variableInterceptor);
                stream.close();
            } else {
                throw new FlowableContentNotSupportedException("Serialized objects are not allowed");
            }

            RestVariable restVariable = null;
            
            if (!async) {
                restVariable = getVariableFromRequestWithoutAccessCheck(instanceId, variableName, responseVariableType, false);
                
                // We are setting the scope because the fetched variable does not have it
                restVariable.setVariableScope(scope);
            }
            
            return restVariable;
            
        } catch (IOException ioe) {
            throw new FlowableIllegalArgumentException("Could not process multipart content", ioe);
            
        } catch (ClassNotFoundException ioe) {
            throw new FlowableContentNotSupportedException(

View on GitHub (pinned to d6d39ce1c6)