{"record":{"id":"703730708698e7f5","repo":"cube-js/cube","slug":"the-count-of-generated-date-ranges-count-for","errorCode":null,"errorMessage":"The count of generated date ranges (${count}) for the request from [${startStr}] to [${endStr}] by ${intervalStr} is over limit (${limit}). Please reduce the requested date interval or use bigger granularity.","messagePattern":"The count of generated date ranges \\((.+?)\\) for the request from \\[(.+?)\\] to \\[(.+?)\\] by (.+?) is over limit \\((.+?)\\)\\. Please reduce the requested date interval or use bigger granularity\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cubejs-backend-shared/src/time.ts","lineNumber":209,"sourceCode":"  Object.entries(parsedInterval).forEach(([key, value]) => {\n    duration.add(value, key as unitOfTime.DurationConstructor);\n  });\n\n  return duration;\n};\n\nfunction checkSeriesForDateRange(intervalStr: string, [startStr, endStr]: QueryDateRange): void {\n  const intervalParsed = parseSqlInterval(intervalStr);\n  const intervalAsSeconds = parsedSqlIntervalToDuration(intervalParsed).asSeconds();\n  const start = moment(startStr);\n  const end = moment(endStr);\n  const rangeSeconds = end.diff(start, 'seconds');\n\n  const limit = 50000; // TODO Make this as configurable soft limit\n  const count = rangeSeconds / intervalAsSeconds;\n\n  if (count > limit) {\n    throw new Error(`The count of generated date ranges (${count}) for the request from [${startStr}] to [${endStr}] by ${intervalStr} is over limit (${limit}). Please reduce the requested date interval or use bigger granularity.`);\n  }\n}\n\nexport const timeSeriesFromCustomInterval = (intervalStr: string, [startStr, endStr]: QueryDateRange, origin: moment.Moment, options: TimeSeriesOptions = { timestampPrecision: 3 }): QueryDateRange[] => {\n  checkSeriesForDateRange(intervalStr, [startStr, endStr]);\n\n  const intervalParsed = parseSqlInterval(intervalStr);\n  const start = moment(startStr);\n  const end = moment(endStr);\n  let alignedStart = alignToOrigin(start, intervalParsed, origin);\n\n  const dates: QueryDateRange[] = [];\n\n  while (alignedStart.isBefore(end)) {\n    const s = alignedStart.clone();\n    alignedStart = addInterval(alignedStart, intervalParsed);\n    dates.push([\n      s.format(`YYYY-MM-DDTHH:mm:ss.${'0'.repeat(options.timestampPrecision)}`),","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-backend-shared/src/time.ts#L191-L227","documentation":"checkSeriesForDateRange (packages/cubejs-backend-shared/src/time.ts:209) computes the number of interval buckets the requested [start,end] range produces (rangeSeconds / intervalAsSeconds) and throws if it exceeds a hard soft limit of 50000. It guards timeSeries/timeSeriesFromCustomInterval against generating enormous arrays of date ranges that would exhaust memory or stall the request.","triggerScenarios":"Calling timeSeries(granularity, ['2000-01-01','2026-01-01']) with a small granularity such as 'second' or 'minute' over many years, or timeSeriesFromCustomInterval('1 second', ...) over a multi-month span, so count = rangeSeconds/intervalAsSeconds > 50000.","commonSituations":"Dashboard widgets requesting second-level granularity over years of history; user-supplied date pickers allowing arbitrarily wide ranges combined with fine granularity; misconfigured custom intervals like '1 millisecond'.","solutions":["Reduce the requested date range (narrow start/end) so the bucket count stays under 50000.","Use a bigger granularity (minute/hour/day instead of second) — as the message itself suggests.","Clamp or round user-supplied ranges in application code before calling timeSeries.","Pre-aggregate upstream (e.g. rollups) and query the coarser series instead."],"exampleFix":"// before\ntimeSeries('second', ['2020-01-01', '2026-01-01']); // ~190M buckets: throws\n\n// after\ntimeSeries('hour', ['2020-01-01', '2026-01-01']); // ~52k → use 'day' to stay safe\ntimeSeries('day', ['2020-01-01', '2026-01-01']);","handlingStrategy":"validation","validationCode":"const MAX = 50000;\nfunction assertSeriesSize(interval: string, [start, end]: [string, string]) {\n  const seconds = (Date.parse(end) - Date.parse(start)) / 1000;\n  const intervalSeconds = /* parse '1 second' etc. */ 1;\n  if (seconds / intervalSeconds > MAX) {\n    throw new Error(`Requested series has >${MAX} buckets; narrow the range or increase granularity`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  return timeSeries(granularity, range, opts);\n} catch (e) {\n  if (/is over limit/.test(String(e))) {\n    return timeSeries('day', range, opts); // coarser fallback\n  }\n  throw e;\n}","preventionTips":["Clamp user-supplied date pickers to a maximum span per granularity","Default dashboards to day/hour granularity, not second","Compute bucket count client-side before requesting","Pre-aggregate long histories into rollups"],"tags":["dates","time-series","limit-exceeded","validation"],"backgroundTag":"date-range-limit-exceeded","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}