{"record":{"id":"9b2e9e5ce36be3d1","repo":"flowable/flowable-engine","slug":"no-deployment-id-provided","errorCode":null,"errorMessage":"No deployment id provided","messagePattern":"No deployment id provided","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-app-engine-rest/src/main/java/org/flowable/app/rest/service/api/repository/AppDeploymentResourceDataResource.java","lineNumber":65,"sourceCode":"    @Autowired\n    protected AppRepositoryService appRepositoryService;\n    \n    @Autowired(required=false)\n    protected AppRestApiInterceptor restApiInterceptor;\n\n    @ApiOperation(value = \"Get an app deployment resource content\", tags = {\"App Deployments\" }, nickname = \"getAppDeploymentResource\",\n            notes = \"The response body will contain the binary resource-content for the requested resource. The response content-type will be the same as the type returned in the resources mimeType property. Also, a content-disposition header is set, allowing browsers to download the file instead of displaying it.\")\n    @ApiResponses(value = {\n            @ApiResponse(code = 200, message = \"Indicates both app deployment and resource have been found and the resource data has been returned.\"),\n            @ApiResponse(code = 404, message = \"Indicates the requested app deployment was not found or there is no resource with the given id present in the app deployment. The status-description contains additional information.\") })\n    @GetMapping(value = \"/app-repository/deployments/{deploymentId}/resourcedata/{resourceName}\")\n    @ResponseBody\n    public byte[] getAppDeploymentResource(@ApiParam(name = \"deploymentId\") @PathVariable(\"deploymentId\") String deploymentId,\n            @ApiParam(name = \"resourceName\") @PathVariable(\"resourceName\") String resourceName,\n            HttpServletResponse response) {\n        \n        if (deploymentId == null) {\n            throw new FlowableIllegalArgumentException(\"No deployment id provided\");\n        }\n        if (resourceName == null) {\n            throw new FlowableIllegalArgumentException(\"No resource name provided\");\n        }\n\n        // Check if deployment exists\n        AppDeployment deployment = appRepositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();\n        if (deployment == null) {\n            throw new FlowableObjectNotFoundException(\"Could not find an app deployment with id '\" + deploymentId);\n        }\n        \n        if (restApiInterceptor != null) {\n            restApiInterceptor.accessDeploymentById(deployment);\n        }\n\n        List<String> resourceList = appRepositoryService.getDeploymentResourceNames(deploymentId);\n\n        if (resourceList.contains(resourceName)) {","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-app-engine-rest/src/main/java/org/flowable/app/rest/service/api/repository/AppDeploymentResourceDataResource.java#L47-L83","documentation":"Thrown by AppDeploymentResourceDataResource.getAppDeploymentResource when the deploymentId path variable is null. In normal Spring MVC routing a path variable cannot be null, so this guard effectively fires when the method is invoked programmatically or bound unusually; it enforces that both deploymentId and resourceName are supplied before any lookup. A twin guard exists for a null resourceName immediately after.","triggerScenarios":"Direct/programmatic invocation of getAppDeploymentResource with a null deploymentId; malformed path mapping or custom controller wiring where the variable is not populated.","commonSituations":"Unit tests calling the method directly; custom routing/forwarding that drops a path segment; template mistakes producing empty segments bound as null by non-standard resolvers.","solutions":["Call the endpoint via its mapped URL /app-repository/deployments/{deploymentId}/resources/{resourceName} with both segments populated.","If invoking the method directly (tests), pass non-null ids.","Review custom interceptor/controller forwarding that may strip path variables.","Also supply resourceName — the same guard fires for it immediately after."],"exampleFix":"// before\nresource.getAppDeploymentResource(null, \"my.app\", response);\n// after\nresource.getAppDeploymentResource(deploymentId, resourceName, response); // both non-null","handlingStrategy":"validation","validationCode":"// Guard before calling (e.g. in tests or programmatic use)\nObjects.requireNonNull(deploymentId, \"deploymentId must not be null\");\nObjects.requireNonNull(resourceName, \"resourceName must not be null\");\nbyte[] data = resource.getAppDeploymentResource(deploymentId, resourceName, response);","typeGuard":"boolean hasPathVars(String deploymentId, String resourceName) {\n    return deploymentId != null && !deploymentId.isEmpty()\n        && resourceName != null && !resourceName.isEmpty();\n}","tryCatchPattern":"try {\n    byte[] data = getAppDeploymentResource(deploymentId, resourceName, response);\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"No deployment id provided\")) {\n        throw new IllegalArgumentException(\"Both deploymentId and resourceName path segments are required\");\n    }\n    throw e;\n}","preventionTips":["Invoke via the mapped URL with both path segments filled.","Never pass null path variables when calling controllers directly in tests.","Review custom forward/redirect logic that could drop segments.","Remember the twin guard for resourceName fires immediately after."],"tags":["rest","validation","null-argument","path-variable"],"backgroundTag":"null-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}