{"record":{"id":"1840f386cdbaa956","repo":"flowable/flowable-engine","slug":"task-id-list-is-empty","errorCode":null,"errorMessage":"Task id list is empty","messagePattern":"Task id list is empty","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/HistoricTaskInstanceQueryImpl.java","lineNumber":716,"sourceCode":"    }\n\n    @Override\n    public HistoricTaskInstanceQuery taskId(String taskId) {\n        if (inOrStatement) {\n            this.currentOrQueryObject.taskId = taskId;\n        } else {\n            this.taskId = taskId;\n        }\n        return this;\n    }\n\n    @Override\n    public HistoricTaskInstanceQuery taskIds(Collection<String> taskIds) {\n        if (taskIds == null) {\n            throw new FlowableIllegalArgumentException(\"Task id list is null\");\n        }\n        if (taskIds.isEmpty()) {\n            throw new FlowableIllegalArgumentException(\"Task id list is empty\");\n        }\n        if (inOrStatement) {\n            this.currentOrQueryObject.taskIds = taskIds;\n        } else {\n            this.taskIds = taskIds;\n        }\n        return this;\n    }\n\n    @Override\n    public HistoricTaskInstanceQuery taskName(String taskName) {\n        if (inOrStatement) {\n            this.currentOrQueryObject.taskName = taskName;\n        } else {\n            this.taskName = taskName;\n        }\n        return this;\n    }","sourceCodeStart":698,"sourceCodeEnd":734,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/HistoricTaskInstanceQueryImpl.java#L698-L734","documentation":"HistoricTaskInstanceQueryImpl.taskIds(Collection) throws FlowableIllegalArgumentException when the collection is non-null but empty. An empty ID list would yield invalid or meaningless IN-clause SQL, so Flowable treats it as a caller mistake. At least one task ID must be supplied, or the call should be skipped.","triggerScenarios":"Calling historicTaskInstanceQuery().taskIds(new ArrayList<>()) or with a collection emptied by prior filtering/removal of processed IDs.","commonSituations":"All IDs consumed/filtered in a batch loop leaving an empty residual list; empty search results from a previous query reused as input; default-initialized collection never populated.","solutions":["Skip the call when the list is empty: only invoke taskIds if !ids.isEmpty().","Populate the collection with the target task IDs before building the query.","Short-circuit the whole query when no IDs remain, since the result set would be empty anyway."],"exampleFix":"// before\nquery.taskIds(pendingIds); // empty\n// after\nif (!pendingIds.isEmpty()) {\n    query.taskIds(pendingIds);\n} else {\n    return Collections.emptyList();\n}","handlingStrategy":"validation","validationCode":"if (taskIds != null && taskIds.isEmpty()) {\n    // return empty result early or populate before querying\n}","typeGuard":"boolean hasTaskIds(Collection<String> ids) {\n    return ids != null && !ids.isEmpty();\n}","tryCatchPattern":"try {\n    query.taskIds(ids);\n} catch (FlowableIllegalArgumentException e) {\n    logger.warn(\"Empty task id list: {}\", e.getMessage());\n}","preventionTips":["Short-circuit to an empty result when the ID list is empty — the query would match nothing anyway.","Re-check list size after filtering/removing entries in batch loops.","Never reuse a mutated collection across iterations without re-validating."],"tags":["flowable","query-builder","empty-collection","argument-validation"],"backgroundTag":"empty-required-field","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"}