cube-js/cube · error · UserError
Granularity "${timeDimension.granularity}" does not exist in
Error message
Granularity "${timeDimension.granularity}" does not exist in dimension ${timeDimension.dimension} What it means
Granularity constructor resolves the requested time dimension granularity. If it is not a predefined granularity (second..year) and cannot be resolved as a custom granularity defined on the dimension, it throws this UserError naming the granularity and dimension.
Source
Thrown at packages/cubejs-schema-compiler/src/adapter/Granularity.ts:48
private readonly query: BaseQuery,
timeDimension: any
) {
this.granularity = timeDimension.granularity;
this.predefinedGranularity = isPredefinedGranularity(this.granularity);
this.queryTimezone = query.timezone || 'UTC';
this.origin = moment.tz(query.timezone).startOf('year'); // Defaults to current year start
if (this.predefinedGranularity) {
this.granularityInterval = `1 ${this.granularity}`;
} else {
const customGranularity = this.query.cacheValue(
['customGranularity', timeDimension.dimension, this.granularity],
() => query.cubeEvaluator
.resolveGranularity([...query.cubeEvaluator.parsePath('dimensions', timeDimension.dimension), 'granularities', this.granularity])
);
if (!customGranularity) {
throw new UserError(`Granularity "${timeDimension.granularity}" does not exist in dimension ${timeDimension.dimension}`);
}
if (!customGranularity.interval) {
const cause = customGranularity.sql
? 'is defined with \'sql\', which is only supported for predefined granularities'
: 'has no interval';
throw new UserError(`Granularity "${this.granularity}" of dimension ${timeDimension.dimension} ${cause}`);
}
this.granularityInterval = customGranularity.interval;
if (customGranularity.origin) {
this.origin = moment.tz(customGranularity.origin, query.timezone);
} else if (customGranularity.offset) {
// Needed because if interval is week-based, offset is expected to be relative to the start of a week
this.fixOriginForWeeksIfNeeded();
this.granularityOffset = customGranularity.offset;
this.origin = addInterval(this.origin, parseSqlInterval(customGranularity.offset));View on GitHub (pinned to 7d981676b3)
Solutions
- Fix the granularity name in the query to a predefined one (second, minute, hour, day, week, month, quarter, year).
- Define the custom granularity on the dimension with an `interval` (e.g. `granularities: { hour4: { interval: '4 hours' } }`).
- Ensure the client version supports custom granularities and the dimension path is correct.
Example fix
// before (query)
timeDimensions: [{ dimension: 'Events.timestamp', granularity: 'hour4' }]
// after (data model)
dimensions: { timestamp: { type: 'time', sql: `timestamp`, granularities: { hour4: { interval: '4 hours' } } } } Defensive patterns
Strategy: validation
Validate before calling
const predefined = ['second','minute','hour','day','week','month','quarter','year'];
if (!predefined.includes(granularity)) {
const dim = dataModel.dimensions[dimName];
if (!dim?.granularities?.[granularity]) throw new Error(`Granularity "${granularity}" not defined on ${dimName}`);
} Try / catch
try { await cube.load(q) } catch (e) { if (/does not exist in dimension/.test(e.message)) { /* retry with 'day' or fix data model */ } else throw e; } Prevention
- Define custom granularities in the data model before clients use them
- Centralize granularity names in shared constants
- Validate query payloads against the schema in API middleware
When it happens
Trigger: A query (REST/GraphQL timeDimensions or SQL API) requests `granularity: 'hour4'` (or any custom name) where the referenced dimension has no matching `granularities` entry, or the granularity name is misspelled.
Common situations: Typos in granularity names ('mont' vs 'month'); clients requesting custom granularities before the data model defines them; case-sensitivity mismatches.
Related errors
- Granularity "${this.granularity}" of dimension ${timeDimensi
- A user's selector doesn't match any of the pre-aggregations
- Data blending query granularities must match
- Data blending query without granularity is not supported
- compareDateRange can only exist for one timeDimension
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/bc2b746d7795299a.
Report an issue: GitHub.