cube-js/cube · error · UserError
Measure filters aren't allowed in ungrouped query
Error message
Measure filters aren't allowed in ungrouped query
What it means
Measure filters are predicates on aggregated values (having-style). Ungrouped queries return raw rows with no aggregation, so filtering on a measure is meaningless there; initUngrouped rejects such queries with this UserError.
Source
Thrown at packages/cubejs-schema-compiler/src/adapter/BaseQuery.js:626
this.timeDimensions.filter(m => !!m.granularity)
.map(m => [m.unescapedAliasName(), `${m.dimension}.${m.granularity}`])
)
);
}
initUngrouped() {
this.ungrouped = this.options.ungrouped;
if (this.ungrouped) {
if (!this.options.allowUngroupedWithoutPrimaryKey && this.join) {
const cubes = R.uniq([this.join.root].concat(this.join.joins.map(j => j.originalTo)));
const primaryKeyNames = cubes.flatMap(c => this.primaryKeyNames(c));
const missingPrimaryKeys = primaryKeyNames.filter(key => !this.dimensions.find(d => d.dimension === key));
if (missingPrimaryKeys.length) {
throw new UserError(`Ungrouped query requires primary keys to be present in dimensions: ${missingPrimaryKeys.map(k => `'${k}'`).join(', ')}. Pass allowUngroupedWithoutPrimaryKey option to disable this check.`);
}
}
if (this.measureFilters.length) {
throw new UserError('Measure filters aren\'t allowed in ungrouped query');
}
}
}
get subQueryDimensions() {
// eslint-disable-next-line no-underscore-dangle
if (!this._subQueryDimensions) {
// eslint-disable-next-line no-underscore-dangle
this._subQueryDimensions = this.collectFromMembers(
false,
this.collectSubQueryDimensionsFor.bind(this),
'collectSubQueryDimensionsFor'
);
}
// eslint-disable-next-line no-underscore-dangle
return this._subQueryDimensions;
}
View on GitHub (pinned to 7d981676b3)
Solutions
- Remove measure filters from the ungrouped query
- Convert the query to grouped (drop ungrouped/raw mode) if metric filtering is needed
- Filter on dimensions or segments instead in ungrouped mode
Example fix
// before
{ ungrouped: true, dimensions: ['Orders.status'], filters: [{ member: 'Orders.count', operator: 'gt', values: [5] }] }
// after
{ ungrouped: true, dimensions: ['Orders.status'], filters: [{ member: 'Orders.status', operator: 'equals', values: ['shipped'] }] } Defensive patterns
Strategy: validation
Validate before calling
function stripMeasureFilters(query, isMeasure) {
if (query.ungrouped) {
query.filters = (query.filters || []).filter(f => !isMeasure(f.member || f.dimension));
}
return query;
}
stripMeasureFilters(query, knownMeasureSet.has.bind(knownMeasureSet)); Try / catch
try {
await cubeApi.load(query);
} catch (e) {
if (/Measure filters aren't allowed in ungrouped/.test(e.message)) {
throw new Error('Remove measure filters or switch to a grouped query');
}
throw e;
} Prevention
- Keep separate filter sets for grouped vs ungrouped views
- In filter UIs, disable measure options when the query is ungrouped
- Filter by dimensions/segments only in raw-row queries
When it happens
Trigger: A query with ungrouped mode whose filters reference a measure (extractDimensionsAndMeasures pushes {measure: ...} entries, landing in measureFilters), e.g. filter on 'Orders.count' in a row-level query.
Common situations: Reusing the same filter set for grouped and ungrouped views; UIs that let users filter by metrics while the query is in raw-row drill-down mode.
Related errors
- Unsupported additional filters for measure ${sourceMeasure}
- member attribute is required for filter ${JSON.stringify(f)}
- You cannot use dimension and measure in same condition: ${JS
- Ungrouped query requires primary keys to be present in dimen
- Dimension-only measure ${measureName} references cubes (${cu
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/5f2f22eb15593c69.
Report an issue: GitHub.