cube-js/cube · error

A user-defined contextToApiScopes function returns an incons

Error message

A user-defined contextToApiScopes function returns an inconsistent type.

What it means

The user-supplied `contextToApiScopes` option must resolve to an array of API scope strings. If it returns null, undefined, or a non-array value (a string, object, Promise resolving to something else), the gateway throws this plain Error while computing the request's API scopes.

Source

Thrown at packages/cubejs-api-gateway/src/gateway.ts:2782

      return {
        securityContext: ctx.securityContext
      };
    };
  }

  protected createContextToApiScopesFn(
    options: ApiGatewayOptions,
  ): ContextToApiScopesFn {
    return options.contextToApiScopes
      ? async (securityContext?: any, defaultApiScopes?: ApiScopes[]) => {
        const scopes = options.contextToApiScopes &&
            await options.contextToApiScopes(
              securityContext,
              defaultApiScopes,
            );
        if (!scopes || !Array.isArray(scopes)) {
          throw new Error(
            'A user-defined contextToApiScopes function returns an inconsistent type.'
          );
        } else {
          scopes.forEach((p) => {
            if (['graphql', 'meta', 'data', 'sql', 'jobs'].indexOf(p) === -1) {
              throw new Error(
                `A user-defined contextToApiScopes function returns a wrong scope: ${p}`
              );
            }
          });
        }
        return scopes;
      }
      : async () => {
        const defaultApiScope = getEnv('defaultApiScope');
        if (defaultApiScope) {
          return defaultApiScope;
        } else {

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Always return an array from contextToApiScopes, e.g. `return ['data']` instead of `return 'data'`.
  2. Ensure every code branch in the function returns a value (add a default branch returning defaultApiScopes).
  3. Await any async lookups (roles DB queries) before returning so the function doesn't return a pending promise mishandled as falsy.
  4. Validate the return shape at the end: throw your own descriptive error if the computed scopes aren't an array.

Example fix

// before
contextToApiScopes: (ctx) => ctx.role === 'admin' ? ['data','meta','sql'] : 'data',
// after
contextToApiScopes: async (ctx, defaultApiScopes) =>
  ctx.role === 'admin' ? ['data', 'meta', 'sql'] : [...defaultApiScopes],
Defensive patterns

Strategy: validation

Validate before calling

async function safeContextToApiScopes(ctx, defaultApiScopes) {
  const scopes = await myContextToApiScopes(ctx, defaultApiScopes);
  if (!Array.isArray(scopes)) throw new TypeError('contextToApiScopes must return an array');
  return scopes;
}

Type guard

function isApiScopesArray(v) {
  return Array.isArray(v) && v.every(s => typeof s === 'string');
}

Try / catch

try {
  const scopes = await contextToApiScopes(ctx, defaults);
} catch (e) {
  if (/inconsistent type/.test(e.message)) {
    // fall back to defaults and alert: contextToApiScopes returned non-array
  }
  throw e;
}

Prevention

When it happens

Trigger: A custom contextToApiScopes(securityContext, defaultApiScopes) implementation returning a single string like 'data', returning undefined on a code path (e.g. missing role branch), or forgetting `await`/`return` inside the async function.

Common situations: Copying an example but short-circuiting with a conditional that falls through; refactoring the function to return a Set or object instead of an array; returning defaultApiScopes directly when it happens to be a falsy/unsupported value.

Related errors


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