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

  1. Remove measure filters from the ungrouped query
  2. Convert the query to grouped (drop ungrouped/raw mode) if metric filtering is needed
  3. 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

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


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