{"record":{"id":"d2cc0319e90a1a50","repo":"Budibase/budibase","slug":"unable-to-assign-roles-license-required","errorCode":null,"errorMessage":"Unable to assign roles - license required.","messagePattern":"Unable to assign roles - license required\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/pro/src/sdk/publicApi/roles.ts","lineNumber":19,"sourceCode":"import { db as dbCore } from \"@budibase/backend-core\"\nimport { isExpandedPublicApiEnabled } from \"../features\"\nimport { db as userDB } from \"../users\"\n\ninterface AssignmentOpts {\n  role?: {\n    appId: string\n    roleId: string\n  }\n  appBuilder?: {\n    appId: string\n  }\n  builder?: boolean\n  admin?: boolean\n}\n\nexport async function assign(userIds: string[], opts: AssignmentOpts) {\n  if (!(await isExpandedPublicApiEnabled())) {\n    throw new Error(\"Unable to assign roles - license required.\")\n  }\n  const users = await userDB.bulkGet(userIds)\n  for (let user of users) {\n    if (opts.role && opts.role.roleId) {\n      const prodWorkspaceId = dbCore.getProdWorkspaceID(opts.role.appId)\n      user.roles[prodWorkspaceId] = opts.role.roleId\n    }\n    if (opts.appBuilder) {\n      const prodWorkspaceId = dbCore.getProdWorkspaceID(opts.appBuilder.appId)\n      const existing = user.builder?.apps || []\n      user.builder = {\n        apps: existing.concat([prodWorkspaceId]),\n      }\n    }\n    if (opts.builder) {\n      user.builder = {\n        global: true,\n      }","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/pro/src/sdk/publicApi/roles.ts#L1-L37","documentation":"The public API roles.assign function only works when the tenant has the 'expanded public API' feature flag enabled, which is license-gated. If the tenant's license does not include expanded public API access, the call is rejected up front with this message before any user records are read. It is a licensing entitlement check, not a permissions or authentication problem.","triggerScenarios":"Calling POST roles assignment via the public API (roles.assign) on a tenant whose license lacks the expanded public API add-on; using public-API role endpoints on the free plan or an expired license.","commonSituations":"Self-hosted or free-tier tenant integrating role management via REST public API; an API integration built on another tenant's plan being pointed at a tenant without the entitlement; license not re-activated after renewal so the feature flag resolves false.","solutions":["Upgrade the tenant's license to one that includes the expanded public API feature","Verify license activation/refresh so isExpandedPublicApiEnabled() resolves true (check licensing cache and re-sync the license)","Use the builder UI or internal API for role assignment instead of the public API if no license upgrade is possible","Wrap the call and surface a clear 'license required' message to end users rather than a generic 500"],"exampleFix":"// before: assuming public API role assignment is always available\nawait publicApi.roles.assign(userIds, { role: { roleId: \"ADMIN\", appId } })\n// after: check the feature flag first\nconst enabled = await isExpandedPublicApiEnabled()\nif (!enabled) {\n  throw new Error(\"Expanded public API requires a license upgrade\")\n}\nawait publicApi.roles.assign(userIds, { role: { roleId: \"ADMIN\", appId } })","handlingStrategy":"validation","validationCode":"const enabled = await isExpandedPublicApiEnabled()\nif (!enabled) throw new Error(\"Expanded public API requires a license upgrade\")","typeGuard":null,"tryCatchPattern":"try {\n  await roles.assign(userIds, opts)\n} catch (err: any) {\n  if (err.message === \"Unable to assign roles - license required.\") {\n    // surface upgrade prompt / use internal API\n  } else { throw err }\n}","preventionTips":["Verify license entitlements before building public-API integrations","Keep license activated/renewed so feature flags stay true","Prefer the builder UI/internal SDK on plans without expanded public API"],"tags":["licensing","public-api","roles","feature-flag"],"backgroundTag":"license-required","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}