{"record":{"id":"cf7bbddd8328c5e0","repo":"cube-js/cube","slug":"date-range-expected-to-be-in-default-ts-format","errorCode":null,"errorMessage":"Date range expected to be in ${DEFAULT_TS_FORMAT} format but ${range} found","messagePattern":"Date range expected to be in (.+?) format but (.+?) found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cubejs-query-orchestrator/src/orchestrator/PreAggregationPartitionRangeLoader.ts","lineNumber":521,"sourceCode":"    }\n    return dateRange;\n  }\n\n  private static checkDataRangeType(range: QueryDateRange) {\n    if (!range) {\n      return;\n    }\n\n    if (range.length !== 2) {\n      throw new Error(`Date range expected to be an array with 2 elements but ${range} found`);\n    }\n\n    if (typeof range[0] !== 'string' || typeof range[1] !== 'string') {\n      throw new Error(`Date range expected to be a string array but ${range} found`);\n    }\n\n    if ((range[0].length !== 23 && range[0].length !== 26) || (range[1].length !== 23 && range[0].length !== 26)) {\n      throw new Error(`Date range expected to be in ${DEFAULT_TS_FORMAT} format but ${range} found`);\n    }\n  }\n\n  public static intersectDateRanges(rangeA: QueryDateRange | null, rangeB: QueryDateRange | null): QueryDateRange | null {\n    PreAggregationPartitionRangeLoader.checkDataRangeType(rangeA);\n    PreAggregationPartitionRangeLoader.checkDataRangeType(rangeB);\n    if (!rangeB) {\n      return rangeA;\n    }\n    if (!rangeA) {\n      return rangeB;\n    }\n    const from = rangeA[0] > rangeB[0] ? rangeA[0] : rangeB[0];\n    const to = rangeA[1] < rangeB[1] ? rangeA[1] : rangeB[1];\n    if (from > to) {\n      return null;\n    }\n    return [","sourceCodeStart":503,"sourceCodeEnd":539,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-query-orchestrator/src/orchestrator/PreAggregationPartitionRangeLoader.ts#L503-L539","documentation":"The final check in checkDataRangeType requires each range endpoint to be a timestamp of length 23 ('yyyy-mm-dd hh:mm:ss.SSS') or 26 (with microseconds) — matching DEFAULT_TS_FORMAT. It throws when the strings parse as strings but have the wrong length/format, ensuring partition boundary math operates on uniform precision timestamps.","triggerScenarios":"Passing short-form dates like '2024-01-01' or '2024-01-01T00:00:00' (ISO 'T' separator, wrong length) into partition range loading; ranges from a different formatting helper producing 10- or 19-char strings.","commonSituations":"Dashboard code building ranges with toISOString() (24 chars, includes 'Z'/'T') instead of Cube's space-separated millisecond format; timezone-aware strings with offsets; legacy code passing 'YYYY-MM-DD'.","solutions":["Format endpoints as 'yyyy-mm-dd hh:mm:ss.SSS' (23 chars) or with microseconds (26 chars), e.g. '2024-01-01 00:00:00.000'.","Use a formatter that replaces 'T' with a space and trims/appends milliseconds instead of toISOString().","Intersect ranges via PreAggregationPartitionRangeLoader.intersectDateRanges, which normalizes inputs, rather than hand-rolling.","Check intermediate range-computation code for string slicing that alters length (e.g., cutting 'Z' but leaving 'T')."],"exampleFix":"// before\ndateRange: [d1.toISOString(), d2.toISOString()] // '2024-01-01T00:00:00.000Z'\n// after\ndateRange: [d1.toISOString().slice(0, 23).replace('T', ' '), d2.toISOString().slice(0, 23).replace('T', ' ')]","handlingStrategy":"validation","validationCode":"const TS_LEN = [23, 26];\nfunction isTsFormat(range) {\n  return isStringPairRange(range) &&\n    range.every(s => TS_LEN.includes(s.length) && s[10] === ' ');\n}\nif (!isTsFormat(range)) throw new Error(`dateRange must be in 'yyyy-mm-dd hh:mm:ss.SSS' format`);","typeGuard":null,"tryCatchPattern":"try {\n  return await loader.loadPreAggregations();\n} catch (e) {\n  if (String(e.message).includes('format but')) {\n    // reformat endpoints to 23/26-char space-separated timestamps and retry\n  }\n  throw e;\n}","preventionTips":["Format endpoints as 'yyyy-mm-dd hh:mm:ss.SSS' (23 chars) or 26 chars with microseconds.","Avoid toISOString() directly — it yields 'T' separators and 'Z' suffix of different length.","Use a shared date formatting utility for all range construction.","Verify intermediate string operations (slice/replace) preserve the 23/26-char length."],"tags":["date-range","format","timestamp","validation"],"backgroundTag":"invalid-date-range-format","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}