flowable/flowable-engine · error · FlowableIllegalArgumentException
File must be of type .bpmn20.xml, .bpmn, .bar or .zip
Error message
File must be of type .bpmn20.xml, .bpmn, .bar or .zip
What it means
FlowableIllegalArgumentException thrown when the uploaded file's name does not have one of the accepted extensions: .bpmn20.xml, .bpmn, .bar or .zip. uploadDeployment dispatches on the file extension (xml is added directly, zip/bar via ZipInputStream) and rejects anything else.
Solutions
- Rename the file to use an accepted extension, e.g. process.bpmn20.xml or process.bpmn
- Package multiple resources into a .bar or .zip archive and upload that
- Export the BPMN XML from the modeler rather than uploading the model source file
- Check the file name is URL-decoded correctly (the extension check uses the decoded query/name)
Example fix
// before mv process.xml process.xml // rejected: unsupported extension curl -F "file=@process.xml" ... // after mv process.xml process.bpmn20.xml curl -F "file=@process.bpmn20.xml" ...
Defensive patterns
Strategy: validation
Validate before calling
const ok = /\.(bpmn20\.xml|bpmn|bar|zip)$/i.test(filename);
if (!ok) throw new Error(`Rename ${filename} to .bpmn20.xml, .bpmn, .bar or .zip before uploading`); Type guard
function isDeployableFile(name) {
return /\.(bpmn20\.xml|bpmn|bar|zip)$/i.test(name);
} Try / catch
try {
deploy(file)
} catch (BadRequest e) {
if (e.message?.includes('File must be of type')) {
throw new Error(`Unsupported extension: ${file.name}. Use .bpmn20.xml, .bpmn, .bar or .zip`);
}
} Prevention
- Standardize on .bpmn20.xml for single process files
- Bundle multiple resources into .bar/.zip archives
- Export from the Flowable modeler as BPMN XML instead of uploading model source files
When it happens
Trigger: Uploading a file named e.g. process.xml, diagram.png, model.bpmnxml, or a BPMN file without any extension to POST /repository/deployments; the extension check happens before any parsing.
Common situations: Files exported with a .xml extension instead of .bpmn20.xml, Camel-cased or missing extensions, renamed files, or uploading the whole model JSON from the Flowable modeler instead of the exported BPMN XML.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- A group or a user is required to create an identity link.
- A group or a user is required to create an identity link.
- A group or a user is required to create an identity link.
- A request body was expected when bulk updating tasks.
- Attachment content is required.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/fbd8e69675021575.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/repository/DeploymentCollectionResource.java:209
if (StringUtils.isEmpty(fileName) || !(fileName.endsWith(".bpmn20.xml") || fileName.endsWith(".bpmn") || fileName.toLowerCase().endsWith(".bar") || fileName.toLowerCase().endsWith(".zip"))) {
fileName = file.getName();
}
if (fileName.endsWith(".bpmn20.xml") || fileName.endsWith(".bpmn")) {
try (final InputStream fileInputStream = file.getInputStream()) {
deploymentBuilder.addInputStream(fileName, fileInputStream);
}
} else if (fileName.toLowerCase().endsWith(".bar") || fileName.toLowerCase().endsWith(".zip")) {
try (InputStream fileInputStream = file.getInputStream();
ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) {
deploymentBuilder.addZipInputStream(zipInputStream);
}
} else {
throw new FlowableIllegalArgumentException("File must be of type .bpmn20.xml, .bpmn, .bar or .zip");
}
if (!decodedQueryStrings.containsKey("deploymentName") || StringUtils.isEmpty(decodedQueryStrings.get("deploymentName"))) {
String fileNameWithoutExtension = fileName.split("\\.")[0];
if (StringUtils.isNotEmpty(fileNameWithoutExtension)) {
fileName = fileNameWithoutExtension;
}
deploymentBuilder.name(fileName);
} else {
deploymentBuilder.name(decodedQueryStrings.get("deploymentName"));
}
if (decodedQueryStrings.containsKey("deploymentKey") && StringUtils.isNotEmpty(decodedQueryStrings.get("deploymentKey"))) {
deploymentBuilder.key(decodedQueryStrings.get("deploymentKey"));
}View on GitHub (pinned to d6d39ce1c6)