{"record":{"id":"3d965f295992b7cb","repo":"flowable/flowable-engine","slug":"taskid-or-processinstanceid-is-required-3d965f","errorCode":null,"errorMessage":"taskId or processInstanceId is required","messagePattern":"taskId or processInstanceId is required","errorType":"validation","errorClass":"ActivitiIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/cmd/GetHistoricIdentityLinksForTaskCmd.java","lineNumber":39,"sourceCode":"import org.activiti.engine.history.HistoricTaskInstance;\nimport org.activiti.engine.impl.interceptor.Command;\nimport org.activiti.engine.impl.interceptor.CommandContext;\nimport org.activiti.engine.impl.persistence.entity.HistoricIdentityLinkEntity;\nimport org.activiti.engine.impl.persistence.entity.HistoricTaskInstanceEntity;\nimport org.activiti.engine.task.IdentityLinkType;\n\n/**\n * @author Frederik Heremans\n */\npublic class GetHistoricIdentityLinksForTaskCmd implements Command<List<HistoricIdentityLink>>, Serializable {\n\n    private static final long serialVersionUID = 1L;\n    protected String taskId;\n    protected String processInstanceId;\n\n    public GetHistoricIdentityLinksForTaskCmd(String taskId, String processInstanceId) {\n        if (taskId == null && processInstanceId == null) {\n            throw new ActivitiIllegalArgumentException(\"taskId or processInstanceId is required\");\n        }\n        this.taskId = taskId;\n        this.processInstanceId = processInstanceId;\n    }\n\n    @Override\n    public List<HistoricIdentityLink> execute(CommandContext commandContext) {\n        if (taskId != null) {\n            return getLinksForTask(commandContext);\n        } else {\n            return getLinksForProcessInstance(commandContext);\n        }\n    }\n\n    @SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n    protected List<HistoricIdentityLink> getLinksForTask(CommandContext commandContext) {\n        HistoricTaskInstanceEntity task = commandContext\n                .getHistoricTaskInstanceEntityManager()","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/cmd/GetHistoricIdentityLinksForTaskCmd.java#L21-L57","documentation":"GetHistoricIdentityLinksForTaskCmd needs at least one of taskId or processInstanceId to query historic identity links. The constructor throws ActivitiIllegalArgumentException when both are null, since the query would have no filter at all.","triggerScenarios":"Calling HistoryService.getHistoricTaskIdentityLinks... style APIs / constructing GetHistoricIdentityLinksForTaskCmd(null, null) directly; typically happens when both caller-supplied ids were null.","commonSituations":"Passing through optional request parameters where neither taskId nor processInstanceId was provided; code paths that assume one of the two was set earlier.","solutions":["Ensure at least one of taskId or processInstanceId is non-null before the call","Add caller-side validation that rejects requests missing both parameters","If querying by process instance, pass the processInstanceId instead of the (null) taskId"],"exampleFix":"// before\nhistoryService.createHistoricTaskInstanceQuery(); // both ids null downstream\nnew GetHistoricIdentityLinksForTaskCmd(taskId, processInstanceId); // both null\n// after\nif (taskId == null && processInstanceId == null) {\n    throw new IllegalArgumentException(\"provide taskId or processInstanceId\");\n}\nnew GetHistoricIdentityLinksForTaskCmd(taskId, processInstanceId);","handlingStrategy":"validation","validationCode":"if (taskId == null && processInstanceId == null) {\n    throw new IllegalArgumentException(\"either taskId or processInstanceId must be provided\");\n}","typeGuard":"boolean hasQueryTarget(String taskId, String processInstanceId) { return taskId != null || processInstanceId != null; }","tryCatchPattern":"try {\n    new GetHistoricIdentityLinksForTaskCmd(taskId, processInstanceId).execute(ctx);\n} catch (ActivitiIllegalArgumentException e) {\n    // reject request: no query target supplied\n}","preventionTips":["Enforce XOR/at-least-one semantics in your API layer before reaching the engine","Default to processInstanceId when task-scoped queries are not applicable","Write integration tests covering both-null input"],"tags":["flowable","activiti","illegal-argument","historic-task"],"backgroundTag":"missing-required-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"}