cube-js/cube · error · Error

${granularity} granularity is not supported

Error message

${granularity} granularity is not supported

What it means

QuestQuery.timeGroupedColumn builds the SQL for a time-dimension granularity grouping using the GRANULARITY_TO_INTERVAL map. If the requested granularity string is not a key of that map, the interval is undefined and the driver throws rather than emitting invalid SQL.

Source

Thrown at packages/cubejs-questdb-driver/src/QuestQuery.ts:116

    return `dateadd('${unit}', ${-number * factor}, ${date})`;
  }

  public addInterval(date: string, interval: string): string {
    const [number, type] = this.parseInterval(interval);
    const { unit, factor } = INTERVAL_TO_QUEST_DATE_UNIT[type];

    return `dateadd('${unit}', ${number * factor}, ${date})`;
  }

  public unixTimestampSql(): string {
    // QuestDB's now() function returns epoch timestamp with microsecond granularity.
    return 'now() / 1000000';
  }

  public timeGroupedColumn(granularity: string, dimension: string): string {
    const interval = GRANULARITY_TO_INTERVAL[granularity];
    if (interval === undefined) {
      throw new Error(`${granularity} granularity is not supported`);
    }
    return `timestamp_floor('${GRANULARITY_TO_INTERVAL[granularity]}', ${dimension})`;
  }

  public dateBin(interval: string, source: string, origin: string): string {
    const { stride, unit, count } = this.questFloorStride(interval);
    // timestamp_floor(stride, ts, origin) only buckets forward from `origin`, so
    // an origin later than the data collapses every row into a single bucket.
    // Shift `origin` back by a whole number of strides (which preserves the bin
    // phase, as flooring is periodic modulo the stride) to just before a fixed
    // anchor that precedes any realistic data.
    const shift = this.dateBinOriginShift(origin, unit, count);
    const shiftedOrigin = shift > 0
      ? `dateadd('${unit}', ${-shift}, cast('${origin}' as timestamp))`
      : `cast('${origin}' as timestamp)`;

    return `timestamp_floor('${stride}', ${source}, ${shiftedOrigin})`;
  }

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Use only granularities supported by the driver (second, minute, hour, day, week, month, quarter, year — check GRANULARITY_TO_INTERVAL in QuestQuery.ts)
  2. Upgrade cubejs-questdb-driver if the needed granularity was added in a newer release
  3. Pre-aggregate/roll up data in the cube schema instead of relying on an unsupported native granularity

Example fix

// before
{ dimension: 'Events.timestamp', granularity: 'fortnight' }
// after
{ dimension: 'Events.timestamp', granularity: 'week' }
Defensive patterns

Strategy: validation

Validate before calling

const supported = ['second','minute','hour','day','week','month','quarter','year']; if (!supported.includes(granularity)) throw new Error(`Unsupported granularity ${granularity} for QuestDB`);

Type guard

function isQuestGranularity(g) { return g in GRANULARITY_TO_INTERVAL; }

Try / catch

try { await cube.query(...); } catch (e) { if (e.message.includes('granularity is not supported')) { /* fall back to 'day' or upgrade driver */ } throw e; }

Prevention

When it happens

Trigger: Compiling a query with a time dimension granularity not supported by the QuestDB driver — e.g. custom granularities passed as arbitrary strings, or granularity names the driver's map lacks.

Common situations: Using cube's custom granularity strings (like 'quarter' in older versions or custom intervals) against a driver version whose GRANULARITY_TO_INTERVAL map does not define them; typos in granularity configuration.

Related errors


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