{"record":{"id":"8a5d063391c19cf6","repo":"flowable/flowable-engine","slug":"after-time-is-null","errorCode":null,"errorMessage":"after time is null","messagePattern":"after time is null","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java","lineNumber":608,"sourceCode":"    }\n    \n    @Override\n    public HistoricCaseInstanceQueryImpl finishedBefore(Date beforeTime) {\n        if (beforeTime == null) {\n            throw new FlowableIllegalArgumentException(\"before time is null\");\n        }\n        if (inOrStatement) {\n            this.currentOrQueryObject.finishedBefore = beforeTime;\n        } else {\n            this.finishedBefore = beforeTime;\n        }\n        return this;\n    }\n    \n    @Override\n    public HistoricCaseInstanceQueryImpl finishedAfter(Date afterTime) {\n        if (afterTime == null) {\n            throw new FlowableIllegalArgumentException(\"after time is null\");\n        }\n        if (inOrStatement) {\n            this.currentOrQueryObject.finishedAfter = afterTime;\n        } else {\n            this.finishedAfter = afterTime;\n        }\n        return this;\n    }\n\n    @Override\n    public HistoricCaseInstanceQueryImpl startedBefore(Date beforeTime) {\n        if (beforeTime == null) {\n            throw new FlowableIllegalArgumentException(\"before time is null\");\n        }\n        if (inOrStatement) {\n            this.currentOrQueryObject.startedBefore = beforeTime;\n        } else {\n            this.startedBefore = beforeTime;","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java#L590-L626","documentation":"FlowableIllegalArgumentException thrown by HistoricCaseInstanceQueryImpl.finishedAfter(Date) in flowable-cmmn-engine when the given date is null. The query API refuses to register a 'finished after' filter without a concrete timestamp, because a null date cannot be translated into a meaningful SQL comparison on the finished-time column of historic case instances. Fail fast at query-build time rather than producing broken SQL at query-execution time.","triggerScenarios":"Calling cmmnHistoryService.createHistoricCaseInstanceQuery().finishedAfter(null); also occurs when calling finishedAfter(variable) inside an or() block and the variable resolving to the Date is null (the null check happens before the inOrStatement branch).","commonSituations":"Developers pass a Date obtained from an optional request parameter, a config value, or a computed value (e.g. endDate of a still-running period) without checking for null; REST/API layers that deserialize a missing 'finishedAfter' field into null and forward it directly into the query builder.","solutions":["Ensure a non-null Date is passed: supply a concrete timestamp before calling finishedAfter().","If the filter is optional, skip calling finishedAfter() entirely when the value is null instead of passing null.","Validate/parse date inputs (e.g. from REST params) and reject or default them before building the query."],"exampleFix":"// before\nquery.finishedAfter(request.getFinishedAfter()); // getFinishedAfter() may return null\n\n// after\nif (request.getFinishedAfter() != null) {\n    query.finishedAfter(request.getFinishedAfter());\n}","handlingStrategy":"validation","validationCode":"if (finishedAfter == null) {\n    throw new IllegalArgumentException(\"finishedAfter must be provided when filtering by finish time\");\n}\nquery.finishedAfter(finishedAfter);","typeGuard":"boolean hasFinishedAfter(Date d) { return d != null; }","tryCatchPattern":"try {\n    query.finishedAfter(afterTime);\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"after time is null\")) {\n        log.warn(\"Ignoring finishedAfter filter: no date supplied\");\n        query = baseQuery(); // rebuild without the filter\n    } else {\n        throw e;\n    }\n}","preventionTips":["Wrap optional date filters in helper methods that apply them only when non-null.","Use java.util.Optional<Date> for nullable filter inputs and ifPresent(query::finishedAfter).","Add bean-validation (@NotNull) on DTO fields carrying query time bounds.","Never call query-builder methods directly with values read straight from request parameters."],"tags":["java","flowable","cmmn","null-check","query-builder"],"backgroundTag":"null-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}