{"record":{"id":"a958801db00c27af","repo":"cube-js/cube","slug":"a-user-defined-contexttoapiscopes-function-returns","errorCode":null,"errorMessage":"A user-defined contextToApiScopes function returns an inconsistent type.","messagePattern":"A user-defined contextToApiScopes function returns an inconsistent type\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cubejs-api-gateway/src/gateway.ts","lineNumber":2782,"sourceCode":"\n      return {\n        securityContext: ctx.securityContext\n      };\n    };\n  }\n\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 {","sourceCodeStart":2764,"sourceCodeEnd":2800,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-api-gateway/src/gateway.ts#L2764-L2800","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Always return an array from contextToApiScopes, e.g. `return ['data']` instead of `return 'data'`.","Ensure every code branch in the function returns a value (add a default branch returning defaultApiScopes).","Await any async lookups (roles DB queries) before returning so the function doesn't return a pending promise mishandled as falsy.","Validate the return shape at the end: throw your own descriptive error if the computed scopes aren't an array."],"exampleFix":"// before\ncontextToApiScopes: (ctx) => ctx.role === 'admin' ? ['data','meta','sql'] : 'data',\n// after\ncontextToApiScopes: async (ctx, defaultApiScopes) =>\n  ctx.role === 'admin' ? ['data', 'meta', 'sql'] : [...defaultApiScopes],","handlingStrategy":"validation","validationCode":"async function safeContextToApiScopes(ctx, defaultApiScopes) {\n  const scopes = await myContextToApiScopes(ctx, defaultApiScopes);\n  if (!Array.isArray(scopes)) throw new TypeError('contextToApiScopes must return an array');\n  return scopes;\n}","typeGuard":"function isApiScopesArray(v) {\n  return Array.isArray(v) && v.every(s => typeof s === 'string');\n}","tryCatchPattern":"try {\n  const scopes = await contextToApiScopes(ctx, defaults);\n} catch (e) {\n  if (/inconsistent type/.test(e.message)) {\n    // fall back to defaults and alert: contextToApiScopes returned non-array\n  }\n  throw e;\n}","preventionTips":["Add a unit test asserting your contextToApiScopes always returns an array for every role","Return [...defaultApiScopes] on any fall-through branch","Use TypeScript ApiScopes[] as the declared return type to catch shape bugs at compile time"],"tags":["configuration","api-scopes","type-error","developer-error"],"backgroundTag":"config-callback-invalid-return","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}