cube-js/cube · error · UserError

Time series queries without dateRange aren't supported

Error message

Time series queries without dateRange aren't supported

What it means

BaseTimeDimension.timeSeries() generates the array of date intervals for a time-series query, which requires an explicit dateRange to compute start/end. Called by values() and seriesSql(), it throws this UserError when the query has no dateRange — without it the series would be unbounded.

Source

Thrown at packages/cubejs-schema-compiler/src/adapter/BaseTimeDimension.ts:268

            // that the interval and the granularity offset are stacked/fits with date range
            if (this.dateRange && (this.granularityObj.isPredefined() ||
              !this.granularityObj.isAlignedWithDateRange([this.dateFromFormatted(), this.dateToFormatted()]))) {
              return this.query.minGranularity(this.granularityObj.minGranularity(), this.dateRangeGranularity());
            }

            // We return the granularity as-is, including custom ones,
            // because baseQuery.granularityHierarchies correctly expands all custom granularities into hierarchies.
            return this.granularityObj.granularity;
          }
        );
    }

    return this.rollupGranularityValue;
  }

  public timeSeries() {
    if (!this.dateRange) {
      throw new UserError('Time series queries without dateRange aren\'t supported');
    }

    if (!this.granularityObj) {
      return [[this.dateFromFormatted(), this.dateToFormatted()]];
    }

    return this.granularityObj.timeSeriesForInterval([this.dateFromFormatted(), this.dateToFormatted()], { timestampPrecision: this.query.timestampPrecision() });
  }

  public resolvedGranularity() {
    return this.granularityObj ? this.granularityObj.resolvedGranularity() : null;
  }

  public resolvedGranularityAsIs() {
    return this.granularityObj ? this.granularityObj.granularity : null;
  }

  public wildcardRange() {

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Add a dateRange to the timeDimension of the query, e.g. dateRange: ['2024-01-01', '2024-03-31']
  2. If an open-ended query is intended, compute a concrete dateRange client-side before sending
  3. For rolling windows, use dateRange expressions like 'last month' that resolve to a bounded range

Example fix

// before
timeDimensions: [{ dimension: 'Orders.createdAt', granularity: 'day' }]
// after
timeDimensions: [{ dimension: 'Orders.createdAt', granularity: 'day', dateRange: ['2024-01-01', '2024-01-31'] }]
Defensive patterns

Strategy: validation

Validate before calling

function validateTimeDimensions(query) {
  for (const td of query.timeDimensions || [])
    if (td.granularity && !td.dateRange) throw new Error('Time-series queries require a dateRange');
}

Type guard

const hasBoundedDateRange = (td) => Array.isArray(td?.dateRange) && td.dateRange.length === 2 && td.dateRange.every(Boolean);

Try / catch

try { const res = await cubeApi.load(q); } catch (e) { if (/Time series queries without dateRange/.test(e.message)) { q.timeDimensions.forEach(td => td.dateRange ||= defaultRange()); return cubeApi.load(q); } throw e; }

Prevention

When it happens

Trigger: Issuing a time-series query (e.g. granularity with series generation, used by charting/rolling window flows) where timeDimensions entry lacks a dateRange — e.g. { dimension: 'Orders.createdAt', granularity: 'day' } with no dateRange, or dateRange: null.

Common situations: BI client requesting a series without a date filter; passing only dateRangeMapped or forgetting dateRange when constructing queries programmatically; using seriesSql-dependent features on unbounded queries.

Related errors


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