cube-js/cube · error · UserError

member attribute is required for filter ${JSON.stringify(f)}

Error message

member attribute is required for filter ${JSON.stringify(f)}

What it means

Cube's BaseQuery flattens query filters into dimension/measure references. Every leaf filter object must identify the member it filters via a 'member' (or legacy 'dimension') property; otherwise the query cannot be compiled. The library throws this UserError when a filter has neither property, because it cannot know which cube member the condition applies to.

Source

Thrown at packages/cubejs-schema-compiler/src/adapter/BaseQuery.js:167

    this.orderHashToString = this.orderHashToString.bind(this);
    this.defaultOrder = this.defaultOrder.bind(this);
    /** @type {ParamAllocator} */
    this.paramAllocator = this.options.paramAllocator || this.newParamAllocator(this.options.expressionParams);
    this.initFromOptions();
  }

  extractDimensionsAndMeasures(filters = []) {
    if (!filters) {
      return [];
    }
    let allFilters = [];
    filters.forEach(f => {
      if (f.and) {
        allFilters = allFilters.concat(this.extractDimensionsAndMeasures(f.and));
      } else if (f.or) {
        allFilters = allFilters.concat(this.extractDimensionsAndMeasures(f.or));
      } else if (!f.member && !f.dimension) {
        throw new UserError(`member attribute is required for filter ${JSON.stringify(f)}`);
      } else if (this.cubeEvaluator.isMeasure(f.member || f.dimension)) {
        allFilters.push({ measure: f.member || f.dimension });
      } else {
        allFilters.push({ dimension: f.member || f.dimension });
      }
    });

    return allFilters;
  }

  keepFilters(filters = [], fn) {
    return filters.map(f => {
      if (f.and) {
        return { and: this.keepFilters(f.and, fn) };
      } else if (f.or) {
        return { or: this.keepFilters(f.or, fn) };
      } else if (!f.member && !f.dimension) {
        throw new UserError(`member attribute is required for filter ${JSON.stringify(f)}`);

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Add a 'member' property to every leaf filter object
  2. Check for typos: the key must be 'member' (or 'dimension')
  3. Log JSON.stringify(f) from the error message to find the offending filter
  4. If filters are built dynamically, guard that the member value is a non-empty string before pushing

Example fix

// before
{ operator: 'equals', values: ['green'] }
// after
{ member: 'Products.color', operator: 'equals', values: ['green'] }
Defensive patterns

Strategy: validation

Validate before calling

function validateFilters(filters) {
  (filters || []).forEach(f => {
    if (f.and) return validateFilters(f.and);
    if (f.or) return validateFilters(f.or);
    if (!f.member && !f.dimension) {
      throw new Error(`Filter missing member: ${JSON.stringify(f)}`);
    }
  });
}
validateFilters(query.filters);

Type guard

const isFilterLeaf = (f) => typeof f === 'object' && f !== null && (typeof f.member === 'string' || typeof f.dimension === 'string');

Try / catch

try {
  await cube.query(query);
} catch (e) {
  if (e instanceof UserError && /member attribute is required for filter/.test(e.message)) {
    console.error('Malformed filter object:', e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a filter object to the query 'filters' array that only has operator/values (e.g. {operator:'equals', values:['x']}) or a typo'd key like 'members' or 'field' instead of 'member'. Also triggered by nested and/or groups containing such malformed leaves, via extractDimensionsAndMeasures.

Common situations: Hand-written JSON queries in API clients, dynamically generated filters where the member variable is undefined/empty, migrating from other query languages that use 'field', or upgrading Cube where filter keys changed.

Related errors


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