{"record":{"id":"a9b5b93b6040908e","repo":"cube-js/cube","slug":"a-user-defined-contexttoapiscopes-function-returns-a9b5b9","errorCode":null,"errorMessage":"A user-defined contextToApiScopes function returns a wrong scope: ${p}","messagePattern":"A user-defined contextToApiScopes function returns a wrong scope: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cubejs-api-gateway/src/gateway.ts","lineNumber":2788,"sourceCode":"\n  protected createContextToApiScopesFn(\n    options: ApiGatewayOptions,\n  ): ContextToApiScopesFn {\n    return options.contextToApiScopes\n      ? async (securityContext?: any, defaultApiScopes?: ApiScopes[]) => {\n        const scopes = options.contextToApiScopes &&\n            await options.contextToApiScopes(\n              securityContext,\n              defaultApiScopes,\n            );\n        if (!scopes || !Array.isArray(scopes)) {\n          throw new Error(\n            'A user-defined contextToApiScopes function returns an inconsistent type.'\n          );\n        } else {\n          scopes.forEach((p) => {\n            if (['graphql', 'meta', 'data', 'sql', 'jobs'].indexOf(p) === -1) {\n              throw new Error(\n                `A user-defined contextToApiScopes function returns a wrong scope: ${p}`\n              );\n            }\n          });\n        }\n        return scopes;\n      }\n      : async () => {\n        const defaultApiScope = getEnv('defaultApiScope');\n        if (defaultApiScope) {\n          return defaultApiScope;\n        } else {\n          return this.contextToApiScopesDefFn();\n        }\n      };\n  }\n\n  protected async assertApiScope(","sourceCodeStart":2770,"sourceCodeEnd":2806,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-api-gateway/src/gateway.ts#L2770-L2806","documentation":"After confirming contextToApiScopes returns an array, Cube validates every element against the allowed scopes: 'graphql', 'meta', 'data', 'sql', 'jobs'. If the function returns an array containing any other string, this Error names the offending scope.","triggerScenarios":"A custom contextToApiScopes returning values like 'read', 'write', 'admin', 'all', or pluralized/typo'd names ('datas', 'metas') that are not among the five permitted scope strings.","commonSituations":"Mapping app-level permissions/roles directly into scopes without translating them to Cube's scope vocabulary; inventing custom scopes expecting them to be honored; typos after upgrading Cube where the allowed list differs from what an old example showed.","solutions":["Map your application roles onto the exact supported scopes: 'graphql', 'meta', 'data', 'sql', 'jobs'.","Fix typos in scope names returned by the function (compare against the error message's offending value).","Introduce an explicit role→scopes mapping object in your config instead of passing raw role strings.","Add a unit test for contextToApiScopes asserting outputs are subsets of the allowed list."],"exampleFix":"// before\ncontextToApiScopes: (ctx) => [ctx.role], // 'admin'\n// after\ncontextToApiScopes: (ctx) => ctx.role === 'admin'\n  ? ['graphql', 'meta', 'data', 'sql', 'jobs']\n  : ['data'],","handlingStrategy":"validation","validationCode":"const ALLOWED = ['graphql', 'meta', 'data', 'sql', 'jobs'];\nfunction validateScopes(scopes) {\n  if (!Array.isArray(scopes)) throw new TypeError('must be array');\n  const bad = scopes.filter(s => !ALLOWED.includes(s));\n  if (bad.length) throw new Error(`Unknown scopes: ${bad.join(', ')}`);\n  return scopes;\n}","typeGuard":"const isApiScope = (s) => ['graphql','meta','data','sql','jobs'].includes(s);\nfunction areValidScopes(v) {\n  return Array.isArray(v) && v.every(isApiScope);\n}","tryCatchPattern":"try {\n  await cubeApi.load(query);\n} catch (e) {\n  if (/wrong scope/.test(e.message)) {\n    // fix the scope mapping in server config using the offending value in the message\n  }\n  throw e;\n}","preventionTips":["Maintain an explicit ROLE_TO_SCOPES map using only the five allowed scope strings","Never pass raw application role names through as scopes","Unit-test the scope mapping against the allowed list on every config change"],"tags":["configuration","api-scopes","validation","developer-error"],"backgroundTag":"invalid-api-scope-value","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}