flowable/flowable-engine · error · FlowableIllegalArgumentException

File must be of type .app

Error message

File must be of type .app

What it means

Thrown by AppDeploymentCollectionResource.uploadDeployment when the uploaded file's name does not have an accepted extension: only '.app' files (single app definitions) or '.zip' files (handled in the if-branch via ZipInputStream) are accepted. Anything else hits the else branch and is rejected with FlowableIllegalArgumentException.

Source

Thrown at modules/flowable-app-engine-rest/src/main/java/org/flowable/app/rest/service/api/repository/AppDeploymentCollectionResource.java:190

            String fileName = file.getOriginalFilename();
            if (StringUtils.isEmpty(fileName) || !(fileName.endsWith(".app") || fileName.toLowerCase().endsWith(".bar") || fileName.toLowerCase().endsWith(".zip"))) {
                fileName = file.getName();
            }

            if (fileName.endsWith(".app")) {
                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 .app");
            }
            
            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)

Solutions

  1. Upload a file with a .app extension (single app definition) or a .zip containing app definitions.
  2. If you have a .bar or raw XML, package it appropriately first (.app or a zip).
  3. Fix the client's Content-Disposition filename so the extension survives the upload.
  4. Check extension case matches what the code expects (lowercase .app/.zip).

Example fix

// before
curl -F 'file=@myapp.bar' .../app-repository/deployments
// after
cp myapp.bar myapp.app
curl -F 'file=@myapp.app' .../app-repository/deployments
Defensive patterns

Strategy: validation

Validate before calling

// Validate the extension before upload
String name = file.getName().toLowerCase();
if (!name.endsWith(".app") && !name.endsWith(".zip")) {
    throw new IllegalArgumentException("Only .app or .zip files are accepted: " + name);
}

Try / catch

try {
    restTemplate.postForEntity(uploadUrl, requestEntity, AppDeploymentResponse.class);
} catch (HttpClientErrorException.BadRequest e) {
    if (e.getResponseBodyAsString().contains("must be of type .app")) {
        throw new IllegalArgumentException("Rename artifact to .app or package it in a .zip");
    }
}

Prevention

When it happens

Trigger: POST /app-repository/deployments with a file whose name has another extension (e.g. .bar, .bpmn20.xml, .xml, or no extension at all).

Common situations: Renaming files without extensions; uploading a process archive (.bar, a BPM-suite convention not accepted here); exporting app definitions without the .app suffix; uppercase extensions if the check is case-sensitive.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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