{"record":{"id":"7be40ddfbf9c4af5","repo":"toeverything/AFFiNE","slug":"bad-request-7be40d","errorCode":"bad_request","errorMessage":"Self-hosted commercial entitlements require a signed license.","messagePattern":"Self-hosted commercial entitlements require a signed license\\.","errorType":"exception","errorClass":"BadRequest","httpStatus":400,"severity":"warning","filePath":"packages/backend/server/src/core/entitlement/service.ts","lineNumber":213,"sourceCode":"      return updated;\n    }\n\n    const created = await this.db.entitlement.create({ data });\n    if (emit) {\n      await this.emitEntitlementChanged(created);\n    }\n    return created;\n  }\n\n  async upsertAdminGrant(input: {\n    targetType: Exclude<TargetType, 'instance'>;\n    targetId: string;\n    plan: string;\n    quantity?: number | null;\n  }) {\n    this.assertAdminGrantInput(input.targetType, input.plan);\n    if (env.selfhosted) {\n      throw new BadRequest(\n        'Self-hosted commercial entitlements require a signed license.'\n      );\n    }\n    const quantity =\n      input.targetType === 'workspace'\n        ? this.normalizedQuantity(input.quantity)\n        : undefined;\n    resolveEntitlementV1({\n      deploymentType: 'cloud',\n      targetType: input.targetType,\n      targetId: input.targetId,\n      plan: input.plan,\n      quantity,\n      now: new Date().toISOString(),\n    });\n\n    const subjectId = this.adminGrantSubjectId(\n      input.targetType,","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/core/entitlement/service.ts#L195-L231","documentation":"EntitlementService.upsertAdminGrant creates commercial plan grants (pro, lifetime_pro, ai, team) and is cloud-only: when env.selfhosted is true it throws BadRequest ('Self-hosted commercial entitlements require a signed license.'). Self-hosted deployments must obtain paid features through an activated signed license key, not manual admin grants.","triggerScenarios":"Calling the admin GraphQL mutation that reaches upsertAdminGrant (user/workspace plan grants from the admin panel) on a self-hosted build; running admin tooling written for the cloud edition against a self-hosted deployment.","commonSituations":"Self-hosters trying to enable team/pro features by hand; scripts copied from cloud ops playbooks; dev machines where the selfhosted env flag is unexpectedly set.","solutions":["On self-hosted, activate a signed license via the license activation API instead of admin grants","If this environment is genuinely cloud, check why env.selfhosted is set (AFFI_NE env/selfhosted config) and correct it","Use only free/built-in features on unlicensed self-hosted installs","Deploy the cloud edition if programmatic admin grants are a hard requirement"],"exampleFix":"// before\nawait entitlement.upsertAdminGrant({ targetType: 'user', targetId, plan: 'pro' });\n\n// after\nif (env.selfhosted) {\n  await licenseService.activate(signedLicenseKey); // commercial features come from the license\n} else {\n  await entitlement.upsertAdminGrant({ targetType: 'user', targetId, plan: 'pro' });\n}","handlingStrategy":"validation","validationCode":"if (env.selfhosted) {\n  throw new Error('use license activation for commercial plans on self-hosted');\n}\nawait entitlement.upsertAdminGrant({ targetType, targetId, plan });","typeGuard":"function isSelfhostedLicenseRequired(e: unknown): boolean {\n  const err = e as { extensions?: { code?: string }; message?: string };\n  return err.extensions?.code === 'bad_request' && /signed license/.test(err.message ?? '');\n}","tryCatchPattern":"try {\n  await upsertAdminGrant(input);\n} catch (e) {\n  if (isSelfhostedLicenseRequired(e)) {\n    return activateLicenseInstead(); // self-hosted path\n  }\n  throw e;\n}","preventionTips":["Gate admin-grant tooling on deployment type (cloud only)","Automate license activation for self-hosted installs that need paid plans","Log the effective env.selfhosted value at startup to catch misconfiguration"],"tags":["entitlement","self-hosted","license","admin","billing"],"backgroundTag":"self-hosted-license-required","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}