{"record":{"id":"1f169fad606fc715","repo":"octobercms/october","slug":"either-date-range-or-start-timestamp-is-required","errorCode":null,"errorMessage":"Either date range or start timestamp is required.","messagePattern":"Either date range or start timestamp is required\\.","errorType":"exception","errorClass":"SystemException","httpStatus":null,"severity":"error","filePath":"modules/dashboard/classes/ReportQueryBuilder.php","lineNumber":673,"sourceCode":"     *\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\n     */\n    protected function buildQuery(\n        bool $skipGrouping = false,\n        bool $skipPagination = false,","sourceCodeStart":655,"sourceCodeEnd":691,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/dashboard/classes/ReportQueryBuilder.php#L655-L691","documentation":"ReportQueryBuilder::validate() requires at least one time-filtering mode: either a date range (dateStart set) or a startTimestamp. When neither is present it throws SystemException('Either date range or start timestamp is required.'). The dashboard report queries are intentionally bounded in time (reporting over an unbounded table would scan everything), so the builder refuses to build an unrestricted aggregate query. Note the pairing guard: dateEnd alone is not sufficient — the check keys on dateStart.","triggerScenarios":"Building a report query with only table + dimension + metrics, never calling setDateRange()/setDateStart()/setStartTimestamp(); passing dateEnd but not dateStart; a widget whose default period resolution returns null for both values (e.g. empty 'range' param from the UI).","commonSituations":"New widget that forgets to forward the time range; UI sends 'range=all' or an empty value which the mapping code turns into no filter at all; data source default period not applied because of a config key rename.","solutions":["Set a bounded window before building: $builder->setDateRange($start, $end) with a non-null start, or $builder->setStartTimestamp($ts).","If you only have an end date, compute a start (e.g. $end->copy()->subDays(30)) so dateStart is set.","Apply a sane default period in the widget/controller when the request carries no range, e.g. last 30 days.","If you genuinely want an unbounded report, pass the earliest possible start timestamp for the table."],"exampleFix":"// before\n$builder->table('orders')->setDimension($dim)->applyMetrics($metrics);\n$rows = $builder->buildQuery()->get();\n\n// after\n$builder->table('orders')->setDimension($dim)->applyMetrics($metrics)\n    ->setStartTimestamp(strtotime('-30 days'));\n$rows = $builder->buildQuery()->get();","handlingStrategy":"validation","validationCode":"// Guarantee a bounded window before building\n$start = $request->input('date_start') ?? now()->subDays(30)->toDateString();\n$builder->setDateRange($start, $request->input('date_end'));\n// note: dateStart must be set — dateEnd alone is not sufficient","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always apply a default reporting period (e.g. last 30 days) in the widget/controller layer.","Remember dateEnd alone does not satisfy the guard — dateStart or startTimestamp must be present.","For 'all time' reports, pass the earliest business-plausible start timestamp."],"tags":["dashboard","report-query-builder","date-filter","required-option-missing"],"backgroundTag":"required-option-missing","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}