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

  1. Use one of the predefined TIME_SERIES granularity keys (e.g. 'day', 'hour', 'week', 'month').
  2. If you need a non-standard interval, use timeSeriesFromCustomInterval('7 days', ...) instead.
  3. 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

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


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/5214f231923edf51. Report an issue: GitHub.