cube-js/cube · error · Error
Unsupported time granularity: ${granularity}
Error message
Unsupported time granularity: ${granularity} What it means
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.
Source
Thrown at packages/cubejs-backend-shared/src/time.ts:242
const s = alignedStart.clone();
alignedStart = addInterval(alignedStart, intervalParsed);
dates.push([
s.format(`YYYY-MM-DDTHH:mm:ss.${'0'.repeat(options.timestampPrecision)}`),
alignedStart.clone()
.subtract(1, 'second')
.format(`YYYY-MM-DDTHH:mm:ss.${'9'.repeat(options.timestampPrecision)}`)
]);
}
return dates;
};
/**
* Returns array of date ranges for a predefined granularity aligned with the start of the year as pivot point
*/
export const timeSeries = (granularity: string, dateRange: QueryDateRange, options: TimeSeriesOptions = { timestampPrecision: 3 }): QueryDateRange[] => {
if (!TIME_SERIES[granularity]) {
throw new Error(`Unsupported time granularity: ${granularity}`);
}
if (!options.timestampPrecision) {
throw new Error(`options.timestampPrecision is required, actual: ${options.timestampPrecision}`);
}
checkSeriesForDateRange(`1 ${granularity}`, dateRange);
// moment.range works with strings
const range = moment.range(<any>dateRange[0], <any>dateRange[1]);
return TIME_SERIES[granularity](range, options.timestampPrecision);
};
export const isPredefinedGranularity = (granularity: string): boolean => !!TIME_SERIES[granularity];
export const FROM_PARTITION_RANGE = '__FROM_PARTITION_RANGE';
View on GitHub (pinned to 7d981676b3)
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.
Example fix
// before
timeSeries('days', ['2024-01-01', '2024-03-01']); // throws
// after
timeSeries('day', ['2024-01-01', '2024-03-01']); Defensive patterns
Strategy: validation
Validate before calling
import { TIME_SERIES } from '@cubejs-backend/shared';
function assertGranularity(g: string) {
if (!(g in TIME_SERIES)) {
throw new Error(`granularity must be one of: ${Object.keys(TIME_SERIES).join(', ')}; got '${g}'`);
}
} Type guard
type PredefinedGranularity = keyof typeof TIME_SERIES;
function isPredefinedGranularity(g: string): g is PredefinedGranularity {
return g in TIME_SERIES;
} Try / catch
try {
return timeSeries(g, range, opts);
} catch (e) {
if (/Unsupported time granularity/.test(String(e))) {
console.error(`Invalid granularity '${g}'; supported: ${Object.keys(TIME_SERIES)}`);
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- The count of generated date ranges (${count}) for the reques
- options.timestampPrecision is required, actual: ${options.ti
- Time series queries without dateRange aren't supported
- Can't parse date: '${from}'
- Can't parse date: '${to}'
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/5214f231923edf51.
Report an issue: GitHub.