{"record":{"id":"d0d2781098b8100b","repo":"flowable/flowable-engine","slug":"before-time-is-null","errorCode":null,"errorMessage":"before time is null","messagePattern":"before 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":595,"sourceCode":"            this.finished = true;\n        }\n        return this;\n    }\n    \n    @Override\n    public HistoricCaseInstanceQueryImpl unfinished() {\n        if (inOrStatement) {\n            this.currentOrQueryObject.unfinished = true;\n        } else {\n            this.unfinished = true;\n        }\n        return this;\n    }\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;","sourceCodeStart":577,"sourceCodeEnd":613,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java#L577-L613","documentation":"HistoricCaseInstanceQueryImpl.finishedBefore() throws FlowableIllegalArgumentException when the beforeTime Date is null. The timestamp is used in a finished-time <= comparison in the generated SQL, so Flowable validates non-null before storing it on the query or the current or-query object.","triggerScenarios":"Calling finishedBefore(null), e.g. when the 'finished before' bound comes from an optional date-range filter whose end bound was not supplied, or from a date parser that returned null on unparseable input.","commonSituations":"Date-range report UIs where only 'finishedAfter' was filled in; the code calls both bound setters regardless. Also occurs after SimpleDateFormat/DateTimeFormatter failures silently yield null.","solutions":["Pass a parsed non-null Date, e.g. finishedBefore(Date.from(instant)).","Only call finishedBefore when the end bound is present; otherwise skip it.","Validate/parse dates explicitly and fail with a clear format error instead of passing null through.","Catch FlowableIllegalArgumentException to return a validation message about the required date bound."],"exampleFix":"// before\nquery.finishedBefore(endDate);\n// after\nif (endDate != null) {\n    query.finishedBefore(endDate);\n}","handlingStrategy":"validation","validationCode":"if (beforeTime != null) {\n    query.finishedBefore(beforeTime);\n}","typeGuard":"boolean hasDate(Date d) {\n    return d != null;\n}","tryCatchPattern":"try {\n    query.finishedBefore(beforeTime);\n} catch (FlowableIllegalArgumentException e) {\n    throw new InvalidRequestException(\"finishedBefore date is required\");\n}","preventionTips":["Apply each date-range bound only when it is present","Parse dates with explicit error handling; never let parse failures yield null silently","Use Optional<Date> or nullable-check helpers at the API boundary","Test report queries with partial (one-sided) date ranges"],"tags":["flowable","cmmn","query","null-argument","date-filter"],"backgroundTag":"null-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"}