{"record":{"id":"b426f4a93a8e9ddf","repo":"flowable/flowable-engine","slug":"could-not-find-the-requested-identity-link-b426f4","errorCode":null,"errorMessage":"Could not find the requested identity link.","messagePattern":"Could not find the requested identity link\\.","errorType":"http","errorClass":"FlowableObjectNotFoundException","httpStatus":404,"severity":"error","filePath":"modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskIdentityLinkResource.java","lineNumber":125,"sourceCode":"    protected IdentityLink getIdentityLink(String family, String identityId, String type, String taskId) {\n        boolean isUser = family.equals(CmmnRestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS);\n\n        // Perhaps it would be better to offer getting a single identitylink\n        // from the API\n        List<IdentityLink> allLinks = taskService.getIdentityLinksForTask(taskId);\n        for (IdentityLink link : allLinks) {\n            boolean rightIdentity = false;\n            if (isUser) {\n                rightIdentity = identityId.equals(link.getUserId());\n            } else {\n                rightIdentity = identityId.equals(link.getGroupId());\n            }\n\n            if (rightIdentity && link.getType().equals(type)) {\n                return link;\n            }\n        }\n        throw new FlowableObjectNotFoundException(\"Could not find the requested identity link.\", IdentityLink.class);\n    }\n}\n","sourceCodeStart":107,"sourceCodeEnd":128,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskIdentityLinkResource.java#L107-L128","documentation":"After validating the family/identity/type arguments, the resource scans the task's identity links for one matching user/group and type. If no such link exists, Flowable throws FlowableableObjectNotFoundException carrying IdentityLink.class, mapping to HTTP 404.","triggerScenarios":"GET or DELETE on /cmmn-runtime/tasks/{taskId}/identitylinks/{family}/{identityId}/{type} where the task exists but no link matches the given identityId+type combination.","commonSituations":"Stale client cache after another actor removed the link; typo in the user/group name or type; attempting to delete a link that was already removed; wrong task id.","solutions":["List existing links (GET /cmmn-runtime/tasks/{taskId}/identitylinks/{family}) to confirm the exact identityId and type before addressing one","Correct the identityId or type spelling","Handle 404 gracefully in the client (idempotent delete) instead of assuming the link always exists"],"exampleFix":"// before\nrestTemplate.delete(\"/cmmn-runtime/tasks/123/identitylinks/users/jonh/candidate\"); // typo, 404\n// after\nList<RestIdentityLink> links = restTemplate.getForObject(\"/cmmn-runtime/tasks/123/identitylinks/users\", List.class);\nif (containsLink(links, \"john\", \"candidate\")) {\n    restTemplate.delete(\"/cmmn-runtime/tasks/123/identitylinks/users/john/candidate\");\n}","handlingStrategy":"try-catch","validationCode":"const links = await get(`/cmmn-runtime/tasks/${taskId}/identitylinks/${family}`);\nconst exists = links.some(l =>\n  (family === 'users' ? l.user : l.group) === identityId && l.type === type);","typeGuard":null,"tryCatchPattern":"try {\n  await del(`/cmmn-runtime/tasks/${taskId}/identitylinks/${family}/${identityId}/${type}`);\n} catch (e) {\n  if (e.status === 404) {\n    return; // already gone: treat delete as idempotent\n  }\n  throw e;\n}","preventionTips":["List current links before GET/DELETE on a specific one","Handle 404 as an expected outcome for deletions","Beware stale caches: re-fetch after concurrent modifications"],"tags":["rest-api","not-found","identity-link"],"backgroundTag":"entity-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"}