cube-js/cube · error · Error

options.contextToApiScopes must be a function

Error message

options.contextToApiScopes must be a function

What it means

registerInterface requires contextToApiScopes to be a function that maps the security context to API scopes for the native SQL interface. If the property is missing or not a function, the interface cannot enforce API scoping, so it throws.

Source

Thrown at packages/cubejs-backend-native/js/index.ts:388

export const resetLogger = (logLevel: LogLevel): void => {
  const native = loadNative();
  native.resetLogger({ logLevel });
};

export const isFallbackBuild = (): boolean => {
  const native = loadNative();
  return native.isFallbackBuild();
};

export type SqlInterfaceInstance = { __typename: 'sqlinterfaceinstance' };

export const registerInterface = async (options: SQLInterfaceOptions): Promise<SqlInterfaceInstance> => {
  if (typeof options !== 'object' && options == null) {
    throw new Error('Argument options must be an object');
  }

  if (typeof options.contextToApiScopes !== 'function') {
    throw new Error('options.contextToApiScopes must be a function');
  }

  if (typeof options.checkAuth !== 'function') {
    throw new Error('options.checkAuth must be a function');
  }

  if (typeof options.checkSqlAuth !== 'function') {
    throw new Error('options.checkSqlAuth must be a function');
  }

  if (typeof options.meta !== 'function') {
    throw new Error('options.meta must be a function');
  }

  if (typeof options.stream !== 'function') {
    throw new Error('options.stream must be a function');
  }

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Add a contextToApiScopes function to the options, e.g. (context) => context.apiScopes.
  2. Check spelling/casing of the property name in the options object.
  3. Ensure the options are built in code (not deserialized from JSON) so functions survive.

Example fix

// before
await registerInterface({ checkAuth, checkSqlAuth, meta, stream });

// after
await registerInterface({
  contextToApiScopes: (context) => context.apiScopes ?? [],
  checkAuth, checkSqlAuth, meta, stream
});
Defensive patterns

Strategy: validation

Validate before calling

if (typeof options.contextToApiScopes !== 'function') {
  throw new Error('options.contextToApiScopes must be provided as a function');
}

Type guard

function hasContextToApiScopes(o) {
  return typeof o?.contextToApiScopes === 'function';
}

Try / catch

try {
  await registerInterface(options);
} catch (e) {
  if (e.message === 'options.contextToApiScopes must be a function') {
    console.error('Add contextToApiScopes: (context) => context.apiScopes to the options.');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling registerInterface() with an options object lacking a contextToApiScopes function, or supplying a non-function value (object, string, undefined).

Common situations: Following outdated docs/examples where the callback was optional or named differently; forgetting the callback when migrating to the native SQL planner; passing config from JSON where functions can't be serialized.

Related errors


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