cube-js/cube · error · UserError
compareDateRange can only exist for one timeDimension
Error message
compareDateRange can only exist for one timeDimension
What it means
The `compareDateRange` option is a convenience that expands one query into multiple date-range variants, so it may be set on at most one timeDimension. Before converting the query, the gateway scans query.timeDimensions and throws this UserError if more than one timeDimension has a non-null compareDateRange.
Source
Thrown at packages/cubejs-api-gateway/src/gateway.ts:2937
type: 'Outgoing network usage',
service: 'api-http',
bytes: Number(res.get('content-length')) || 0,
path: req.path,
}, req.context);
});
if (next) {
next();
}
};
protected compareDateRangeTransformer(query) {
let queryCompareDateRange;
let compareDateRangeTDIndex;
(query.timeDimensions || []).forEach((td, index) => {
if (td.compareDateRange != null) {
if (queryCompareDateRange != null) {
throw new UserError('compareDateRange can only exist for one timeDimension');
}
queryCompareDateRange = td.compareDateRange;
compareDateRangeTDIndex = index;
}
});
if (queryCompareDateRange == null) {
return query;
}
return queryCompareDateRange.map((dateRange) => ({
...R.clone(query),
timeDimensions: query.timeDimensions.map((td, index) => {
if (compareDateRangeTDIndex === index) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { compareDateRange, ...timeDimension } = td;
return {View on GitHub (pinned to 7d981676b3)
Solutions
- Keep compareDateRange on only one timeDimension; remove it from the others.
- If you need comparisons across multiple dimensions, split into separate API requests and merge results client-side.
- Use explicit dateRange arrays per timeDimension plus separate queries instead of the compareDateRange shortcut when comparing multiple dimensions.
Example fix
// before
timeDimensions: [
{ dimension: 'Events.date', compareDateRange: ['2024-01-01','2024-01-31'] },
{ dimension: 'Users.created', compareDateRange: ['2023-01-01','2023-01-31'] }
]
// after
timeDimensions: [
{ dimension: 'Events.date', compareDateRange: ['2024-01-01','2024-01-31'] },
{ dimension: 'Users.created', dateRange: ['2023-01-01','2023-01-31'] }
] Defensive patterns
Strategy: validation
Validate before calling
function validateCompareDateRange(query) {
const count = (query.timeDimensions || []).filter(td => td.compareDateRange != null).length;
if (count > 1) throw new Error('compareDateRange allowed on at most one timeDimension');
} Type guard
function hasAtMostOneCompareDateRange(query) {
return (query.timeDimensions || []).filter(td => td.compareDateRange != null).length <= 1;
} Try / catch
try {
await cubeApi.load(query);
} catch (e) {
if (e instanceof Error && e.message.includes('compareDateRange')) {
// strip compareDateRange from all but one timeDimension and retry
}
throw e;
} Prevention
- Normalize queries in your query-builder layer before sending: keep compareDateRange on one dimension only
- Constrain the UI so the comparison picker applies to a single timeDimension
- Add a JSON-schema or zod validation for outgoing queries
When it happens
Trigger: Submitting a /cubejs-api/v1/load query whose timeDimensions array contains two or more entries each with `compareDateRange` set — e.g. comparing two different date ranges for two different dimensions in one request.
Common situations: Programmatic query builders accumulating compareDateRange across dimensions; UI clients letting users pick a comparison range per dimension; hand-editing a JSON query copied from another example.
Related errors
- member attribute is required for filter ${JSON.stringify(f)}
- Incorrect timezone ${this.timezone}
- Can't parse date: '${from}'
- Can't parse date: '${to}'
- Can't parse date: '${dateString}'
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/aecca313c26202d4.
Report an issue: GitHub.