cube-js/cube · error · Error

Access policy cannot have both 'group' and 'groups' properti

Error message

Access policy cannot have both 'group' and 'groups' properties.
Policy in cube '${cube.name}' has group '${groupDisplay}' and groups '${groupsDisplay}'.
Use either 'group' or 'groups', not both.

What it means

Access policies accept either the singular 'group' or plural 'groups' property to declare which groups a policy applies to. A policy defining both is ambiguous, so getApplicablePolicies throws with the offending values and cube name.

Source

Thrown at packages/cubejs-server-core/src/core/CompilerApi.ts:433

  protected hashRequestContext(context: Context): string {
    if (!context.__hash) {
      context.__hash = crypto.createHash('md5').update(JSON.stringify(context)).digest('hex');
    }
    return context.__hash;
  }

  protected async getApplicablePolicies(cube: EvaluatedCube, context: Context, compilers: Compiler): Promise<any[]> {
    const cache = compilers.compilerCache.getRbacCacheInstance();
    const cacheKey = `${cube.name}_${this.hashRequestContext(context)}`;
    if (!cache.has(cacheKey)) {
      const userGroups = await this.getGroupsFromContext(context);
      const policies = cube.accessPolicy.filter((policy: AccessPolicyDefinition) => {
        // Validate that policy doesn't have both group and groups
        if (policy.group && policy.groups) {
          const groupDisplay = Array.isArray(policy.group) ? policy.group.join(', ') : policy.group;
          const groupsDisplay = Array.isArray(policy.groups) ? policy.groups.join(', ') : policy.groups;
          throw new Error(
            `Access policy cannot have both 'group' and 'groups' properties.\nPolicy in cube '${cube.name}' has group '${groupDisplay}' and groups '${groupsDisplay}'.\nUse either 'group' or 'groups', not both.`
          );
        }

        const evaluatedConditions = (policy.conditions || []).map(
          (condition: any) => compilers.cubeEvaluator.evaluateContextFunction(cube, condition.if, context)
        );

        // Check if policy matches by group or groups
        let hasAccess = false;

        if (policy.group) {
          hasAccess = this.userHasGroup(userGroups, policy.group);
        } else if (policy.groups) {
          hasAccess = this.userHasGroup(userGroups, policy.groups);
        } else {
          // A policy without group/groups applies to everyone
          hasAccess = this.userHasGroup(userGroups, '*');

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Remove the legacy 'group' key and keep only 'groups' (preferred plural array form)
  2. Or keep only 'group' if a single group is intended
  3. Search your schema for accessPolicy blocks containing both keys in the named cube

Example fix

// before
accessPolicy: [{ group: 'admin', groups: ['admin', 'analyst'] }]
// after
accessPolicy: [{ groups: ['admin', 'analyst'] }]
Defensive patterns

Strategy: validation

Validate before calling

function validatePolicy(p) {
  if (p.group && p.groups) throw new Error(`accessPolicy has both 'group' and 'groups': ${JSON.stringify(p)}`);
}

Type guard

const isPolicyGroups = (p: AccessPolicyDefinition): p is AccessPolicyDefinition & { group?: never } => !('group' in p) || !('groups' in p);

Try / catch

try { const policies = getApplicablePolicies(cubes, context, compilers); } catch (e) { if (/both 'group' and 'groups'/.test(e.message)) { /* flag offending cube */ } else throw e; }

Prevention

When it happens

Trigger: A cube's accessPolicy entry includes both keys, typically after migrating config from the old singular form to the plural array form without removing 'group'.

Common situations: Copy-pasted policy definitions, incremental migration where one policy still has the legacy 'group' alongside new 'groups', or code-generated schemas emitting both keys.

Related errors


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