{"record":{"id":"5214f231923edf51","repo":"cube-js/cube","slug":"unsupported-time-granularity-granularity","errorCode":null,"errorMessage":"Unsupported time granularity: ${granularity}","messagePattern":"Unsupported time granularity: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cubejs-backend-shared/src/time.ts","lineNumber":242,"sourceCode":"    const s = alignedStart.clone();\n    alignedStart = addInterval(alignedStart, intervalParsed);\n    dates.push([\n      s.format(`YYYY-MM-DDTHH:mm:ss.${'0'.repeat(options.timestampPrecision)}`),\n      alignedStart.clone()\n        .subtract(1, 'second')\n        .format(`YYYY-MM-DDTHH:mm:ss.${'9'.repeat(options.timestampPrecision)}`)\n    ]);\n  }\n\n  return dates;\n};\n\n/**\n * Returns array of date ranges for a predefined granularity aligned with the start of the year as pivot point\n */\nexport const timeSeries = (granularity: string, dateRange: QueryDateRange, options: TimeSeriesOptions = { timestampPrecision: 3 }): QueryDateRange[] => {\n  if (!TIME_SERIES[granularity]) {\n    throw new Error(`Unsupported time granularity: ${granularity}`);\n  }\n\n  if (!options.timestampPrecision) {\n    throw new Error(`options.timestampPrecision is required, actual: ${options.timestampPrecision}`);\n  }\n\n  checkSeriesForDateRange(`1 ${granularity}`, dateRange);\n\n  // moment.range works with strings\n  const range = moment.range(<any>dateRange[0], <any>dateRange[1]);\n\n  return TIME_SERIES[granularity](range, options.timestampPrecision);\n};\n\nexport const isPredefinedGranularity = (granularity: string): boolean => !!TIME_SERIES[granularity];\n\nexport const FROM_PARTITION_RANGE = '__FROM_PARTITION_RANGE';\n","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-backend-shared/src/time.ts#L224-L260","documentation":"timeSeries() in packages/cubejs-backend-shared/src/time.ts only supports a fixed set of predefined granularities indexed by TIME_SERIES (aligned to the start of the year as pivot). If the passed granularity string is not a key of TIME_SERIES, the lookup returns undefined and the function throws. It is a fail-fast guard against typos or unsupported interval names.","triggerScenarios":"Calling timeSeries('fortnight', range) or timeSeries('mins', range) — any string not present in TIME_SERIES (supported keys are granularities like second/minute/hour/day/week/month/quarter/year).","commonSituations":"Typo in granularity ('weely'), pluralization mistakes ('days' vs 'day'), granularity read from config/env that doesn't match the supported set, migrating code from a library with a different granularity vocabulary.","solutions":["Use one of the predefined TIME_SERIES granularity keys (e.g. 'day', 'hour', 'week', 'month').","If you need a non-standard interval, use timeSeriesFromCustomInterval('7 days', ...) instead.","Normalize/validate the granularity string (trim, lowercase, singularize) before calling timeSeries."],"exampleFix":"// before\ntimeSeries('days', ['2024-01-01', '2024-03-01']); // throws\n\n// after\ntimeSeries('day', ['2024-01-01', '2024-03-01']);","handlingStrategy":"validation","validationCode":"import { TIME_SERIES } from '@cubejs-backend/shared';\nfunction assertGranularity(g: string) {\n  if (!(g in TIME_SERIES)) {\n    throw new Error(`granularity must be one of: ${Object.keys(TIME_SERIES).join(', ')}; got '${g}'`);\n  }\n}","typeGuard":"type PredefinedGranularity = keyof typeof TIME_SERIES;\nfunction isPredefinedGranularity(g: string): g is PredefinedGranularity {\n  return g in TIME_SERIES;\n}","tryCatchPattern":"try {\n  return timeSeries(g, range, opts);\n} catch (e) {\n  if (/Unsupported time granularity/.test(String(e))) {\n    console.error(`Invalid granularity '${g}'; supported: ${Object.keys(TIME_SERIES)}`);\n  }\n  throw e;\n}","preventionTips":["Use a union/enum type for granularity in your app config","Validate granularity from env/config at startup","Use timeSeriesFromCustomInterval for non-standard intervals","Add an allowlist check where granularity enters from user input"],"tags":["time-series","granularity","validation","runtime"],"backgroundTag":"unsupported-time-granularity","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}