{"record":{"id":"bb2201289e43e2a9","repo":"n8n-io/n8n","slug":"plan-lacks-license-for-this-feature","errorCode":null,"errorMessage":"Plan lacks license for this feature","messagePattern":"Plan lacks license for this feature","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"packages/cli/src/controller.registry.ts","lineNumber":229,"sourceCode":"\t\t}\n\n\t\tif (route.accessScope) {\n\t\t\tmiddlewares.push(this.createScopedMiddleware(route.accessScope));\n\t\t}\n\n\t\tmiddlewares.push(...controllerMiddlewares);\n\n\t\tif (route.middlewares) {\n\t\t\tmiddlewares.push(...route.middlewares);\n\t\t}\n\n\t\treturn middlewares;\n\t}\n\n\tprivate createLicenseMiddleware(feature: BooleanLicenseFeature): RequestHandler {\n\t\treturn (_req, res, next) => {\n\t\t\tif (!this.license.isLicensed(feature)) {\n\t\t\t\tres.status(403).json({ status: 'error', message: 'Plan lacks license for this feature' });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tnext();\n\t\t};\n\t}\n\n\tprivate createScopedMiddleware(accessScope: AccessScope): RequestHandler {\n\t\treturn async (req, res, next) => {\n\t\t\tif (!isAuthenticatedRequest(req)) throw new UnauthenticatedError();\n\t\t\tif (!req.user) throw new UnauthenticatedError();\n\n\t\t\tconst { scope, globalOnly } = accessScope;\n\n\t\t\ttry {\n\t\t\t\tif (!(await userHasScopes(req.user, [scope], globalOnly, req.params))) {\n\t\t\t\t\tres.status(403).json({\n\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\tmessage: RESPONSE_ERROR_MESSAGES.MISSING_SCOPE,","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/cli/src/controller.registry.ts#L211-L247","documentation":"Returned as a 403 JSON response by `ControllerRegistry.createLicenseMiddleware` when a route declares `@Licensed(feature)` and `license.isLicensed(feature)` returns false at request time. The body is static: `{ status: 'error', message: 'Plan lacks license for this feature' }`. Unlike error 1327 (thrown at boot), this is per-request and only blocks the gated endpoint.","triggerScenarios":"Calling any `@Licensed` endpoint (e.g. `feat:aiBuilder`, advanced RBAC endpoints, source control) without the corresponding entitlement in the active license.","commonSituations":"Community/Starter license hitting an Enterprise-only endpoint; trial license expired; license not yet activated on a fresh instance; feature flag enabled but entitlement missing.","solutions":["Activate a license that includes the feature via `N8N_LICENSE_ACTIVATION_KEY`.","Verify with `n8n license:info` that the feature is listed.","If the license should already cover it, ensure `license.autoRenewalEnabled=true` and the instance can reach the license server.","Avoid calling the gated endpoint if you do not have the entitlement."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!await license.isLicensed(feature)) {\n  throw new Error(`Plan lacks entitlement for ${feature}; activate a qualifying license.`);\n}","typeGuard":null,"tryCatchPattern":"try { await api.post('/licensed-endpoint'); } catch (e) { if (e.response?.status === 403 && /license/i.test(e.response.data?.message)) { await activateLicense(); await retry(); } else throw e; }","preventionTips":["Call `n8n license:info` in CI to confirm entitlements before deploying gated features.","Surface a feature-disabled UI state instead of letting users hit the 403."],"tags":["api","license","rest","authorization","user-error"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}