{"record":{"id":"0b90d32a49bb666f","repo":"flowable/flowable-engine","slug":"task-taskid-does-not-have-an-attachment-with-i-0b90d3","errorCode":null,"errorMessage":"Task '{taskId}' does not have an attachment with id '{attachmentId}'.","messagePattern":"Task '(.+?)' does not have an attachment with id '(.+?)'\\.","errorType":"http","errorClass":"FlowableObjectNotFoundException","httpStatus":404,"severity":"error","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskAttachmentResource.java","lineNumber":55,"sourceCode":" * @author Frederik Heremans\n */\n@RestController\n@Api(tags = { \"Task Attachments\" }, authorizations = { @Authorization(value = \"basicAuth\") })\npublic class TaskAttachmentResource extends TaskBaseResource {\n\n    @ApiOperation(value = \"Get an attachment on a task\", tags = { \"Task Attachments\" })\n    @ApiResponses(value = {\n            @ApiResponse(code = 200, message = \"Indicates the task and attachment were found and the attachment is returned.\"),\n            @ApiResponse(code = 404, message = \"Indicates the requested task was not found or the tasks does not have a attachment with the given ID.\")\n    })\n    @GetMapping(value = \"/runtime/tasks/{taskId}/attachments/{attachmentId}\", produces = \"application/json\")\n    public AttachmentResponse getAttachment(@ApiParam(name = \"taskId\") @PathVariable(\"taskId\") String taskId, @ApiParam(name = \"attachmentId\") @PathVariable(\"attachmentId\") String attachmentId) {\n\n        HistoricTaskInstance task = getHistoricTaskFromRequest(taskId);\n\n        Attachment attachment = taskService.getAttachment(attachmentId);\n        if (attachment == null || !task.getId().equals(attachment.getTaskId())) {\n            throw new FlowableObjectNotFoundException(\"Task '\" + task.getId() + \"' does not have an attachment with id '\" + attachmentId + \"'.\", Comment.class);\n        }\n\n        return restResponseFactory.createAttachmentResponse(attachment);\n    }\n\n    @ApiOperation(value = \"Delete an attachment on a task\", tags = { \"Task Attachments\"}, code = 204)\n    @ApiResponses(value = {\n            @ApiResponse(code = 204, message = \"Indicates the task and attachment were found and the attachment is deleted. Response body is left empty intentionally.\"),\n            @ApiResponse(code = 404, message = \"Indicates the requested task was not found or the tasks does not have a attachment with the given ID.\")\n    })\n    @DeleteMapping(value = \"/runtime/tasks/{taskId}/attachments/{attachmentId}\")\n    @ResponseStatus(HttpStatus.NO_CONTENT)\n    public void deleteAttachment(@ApiParam(name = \"taskId\") @PathVariable(\"taskId\") String taskId, @ApiParam(name = \"attachmentId\") @PathVariable(\"attachmentId\") String attachmentId) {\n\n        Task task = getTaskFromRequestWithoutAccessCheck(taskId);\n\n        Attachment attachment = taskService.getAttachment(attachmentId);\n        if (attachment == null || !task.getId().equals(attachment.getTaskId())) {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskAttachmentResource.java#L37-L73","documentation":"FlowableObjectNotFoundException thrown when reading a single task attachment: no attachment exists with the given id, or it belongs to a different task than the path parameter. Note it declares Comment.class as the entity class — a copy-paste artifact — but the semantics are attachment-not-found.","triggerScenarios":"GET /runtime/tasks/{taskId}/attachments/{attachmentId} where taskService.getAttachment(attachmentId) is null or the attachment's taskId differs from the path taskId.","commonSituations":"Attachment id from another task or process; attachment deleted earlier; wrong REST deployment/tenant pointing at another database; stale cached ids in client code.","solutions":["List the task's attachments (GET .../attachments) and use a returned id","Confirm the taskId/attachmentId pair from the original creation response","Point the client at the correct database/tenant","Check the attachment was not deleted by another process"],"exampleFix":"// before\nGET /runtime/tasks/101/attachments/wrong-id\n// after\nGET /runtime/tasks/101/attachments  // then\nGET /runtime/tasks/101/attachments/{id-from-list}","handlingStrategy":"validation","validationCode":"const list = await api.getTaskAttachments(taskId);\nif (!list.some(a => a.id === attachmentId)) throw new Error('attachmentId not in task attachment list');","typeGuard":null,"tryCatchPattern":"try { return await api.getTaskAttachment(taskId, attachmentId); } catch (e) { if (e.status === 404) return null; throw e; }","preventionTips":["Always derive attachmentId from the task's own attachment list","Treat 404 as expected for stale ids and refresh the list","Confirm environment/tenant before querying"],"tags":["rest","not-found","attachments"],"backgroundTag":"record-not-found","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}