{"record":{"id":"8e4d57b05d079e34","repo":"octobercms/october","slug":"cannot-use-both-date-range-and-timestamp-filtering","errorCode":null,"errorMessage":"Cannot use both date range and timestamp filtering.","messagePattern":"Cannot use both date range and timestamp filtering\\.","errorType":"exception","errorClass":"SystemException","httpStatus":null,"severity":"error","filePath":"modules/dashboard/classes/ReportQueryBuilder.php","lineNumber":669,"sourceCode":"    //\n\n    /**\n     * validate ensures required properties are set\n     *\n     * @throws SystemException\n     */\n    protected function validate(): void\n    {\n        if (!$this->tableName) {\n            throw new SystemException('Table name is required.');\n        }\n\n        if (!$this->dimension) {\n            throw new SystemException('Dimension is required.');\n        }\n\n        if (($this->dateStart || $this->dateEnd) && $this->startTimestamp !== null) {\n            throw new SystemException('Cannot use both date range and timestamp filtering.');\n        }\n\n        if (!$this->dateStart && $this->startTimestamp === null) {\n            throw new SystemException('Either date range or start timestamp is required.');\n        }\n\n        if ($this->limit !== null && $this->pagination !== null) {\n            throw new SystemException('Cannot use both limit and pagination.');\n        }\n    }\n\n    /**\n     * buildQuery constructs the query builder\n     *\n     * @param bool $skipGrouping\n     * @param bool $skipPagination\n     * @param array $forceMetrics\n     * @return QueryBuilder","sourceCodeStart":651,"sourceCodeEnd":687,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/dashboard/classes/ReportQueryBuilder.php#L651-L687","documentation":"ReportQueryBuilder::validate() forbids mixing the two supported time-filtering modes: an explicit date range (dateStart/dateEnd on a date column) and timestamp-based filtering (startTimestamp). Setting any of dateStart/dateEnd together with a non-null startTimestamp throws SystemException('Cannot use both date range and timestamp filtering.'). The builder generates different WHERE clauses for each mode, so the combination is ambiguous and rejected rather than guessed.","triggerScenarios":"Calling both $builder->setDateRange($start, $end) (or setDateStart/setDateEnd) and $builder->setStartTimestamp($ts) on the same builder before it validates; a widget config that carries both a human 'range' preset (converted to dates) and an explicit timestamp, with merging code that keeps both.","commonSituations":"Dashboard UI sends a saved preset range plus a manually typed timestamp after a config merge; refactoring from timestamp filtering to date ranges while the old property is still set in a base class or cloned builder; copy-pasting setup code from another builder instance.","solutions":["Choose one mode: keep setDateStart/setDateEnd for date-column filtering and drop setStartTimestamp, or vice versa.","When merging request/config input, explicitly null out the other mode: if timestamp provided, clear dateStart/dateEnd before building.","If both arrive from the UI, add precedence logic (e.g. timestamp wins) that clears the losing pair before validate() runs.","Check cloned/reused builder instances — reset startTimestamp (or dates) between builds."],"exampleFix":"// before\n$builder->setDateRange('2026-01-01', '2026-02-01')->setStartTimestamp(1767225600);\n\n// after\n$builder->setDateRange('2026-01-01', '2026-02-01');\n// or, timestamp mode only:\n// $builder->setStartTimestamp(1767225600);","handlingStrategy":"validation","validationCode":"// Enforce one time-filter mode before configuring the builder\nif ($request->filled('start_timestamp')) {\n    $builder->setStartTimestamp((int) $request->input('start_timestamp'));\n} else {\n    $builder->setDateRange($request->input('date_start'), $request->input('date_end'));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call both setDateRange/setDateStart/setDateEnd and setStartTimestamp on one builder instance.","When merging saved widget properties with request input, clear the losing time-filter mode explicitly.","Reset builder state (or use fresh instances) when building multiple queries in a loop."],"tags":["dashboard","report-query-builder","date-filter","conflicting-options"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}