{"record":{"id":"6a704968613740b3","repo":"toeverything/AFFiNE","slug":"internal-server-error-6a7049","errorCode":"internal_server_error","errorMessage":"An internal error occurred.","messagePattern":"An internal error occurred\\.","errorType":"exception","errorClass":"InternalServerError","httpStatus":500,"severity":"error","filePath":"packages/backend/server/src/plugins/license/service.ts","lineNumber":463,"sourceCode":"        e instanceof UserFriendlyError &&\n        e.name !== 'internal_server_error'\n      ) {\n        this.event.emit('workspace.subscription.canceled', {\n          workspaceId: license.workspaceId,\n          plan: SubscriptionPlan.SelfHostedTeam,\n          recurring: SubscriptionRecurring.Monthly,\n        });\n        await this.entitlement.revokeBySubject('selfhost_license', license.key);\n      }\n\n      return null;\n    }\n  }\n\n  private remoteLicense(response: LicenseResponse) {\n    this.throwRemoteLicenseError(response.error);\n    if (!response.license) {\n      throw new InternalServerError('Invalid AFFiNE Pro license response.');\n    }\n    return response.license;\n  }\n\n  private remoteCommand(response: CommandResponse) {\n    this.throwRemoteLicenseError(response.error);\n  }\n\n  private remotePortal(response: PortalResponse) {\n    this.throwRemoteLicenseError(response.error);\n    if (!response.url) {\n      throw new InternalServerError('Invalid AFFiNE Pro portal response.');\n    }\n    return { url: response.url };\n  }\n\n  private throwRemoteLicenseError(\n    error?: LicenseError | null","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/plugins/license/service.ts#L445-L481","documentation":"remoteLicense() normalizes the response from the AFFiNE Pro license cloud API (activate/deactivate). After throwRemoteLicenseError confirms error is absent, an intact response must contain response.license; if it does not, the response is malformed and InternalServerError('Invalid AFFiNE Pro license response.') is thrown. This signals an unexpected protocol violation from the license service rather than a client mistake.","triggerScenarios":"licenseClient.activate({ licenseKey }) or deactivate returning HTTP 2xx with an empty or schema-breaking body — e.g. a proxy (nginx/Cloudflare) intercepting and rewriting the response, an API version change on app.affine.pro, or a truncated response.","commonSituations":"Self-hosted deployments behind corporate proxies that strip or replace response bodies; transient CDN corruption; upstream deploying a breaking API change; responses buffered/served from cache incorrectly.","solutions":["Retry once after a short delay — malformed 2xx bodies are usually transient.","Inspect egress: disable any corporate proxy/SSL-inspection rewriting for https://app.affine.pro, or fix the reverse-proxy body-filter rules.","Capture the raw response (log licenseClient traffic in dev) and check the AFFiNE Pro status page / support if the shape changed — a persistent failure indicates an upstream contract change requiring a server update."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"function isInternalServerError(e: unknown): e is InternalServerError {\n  return e instanceof InternalServerError;\n}","tryCatchPattern":"async function withLicenseRetry<T>(fn: () => Promise<T>, attempts = 2): Promise<T> {\n  for (let i = 0; ; i++) {\n    try {\n      return await fn();\n    } catch (e) {\n      if (i >= attempts || !(e instanceof InternalServerError)) throw e;\n      await new Promise(r => setTimeout(r, 500 * 2 ** i));\n    }\n  }\n}","preventionTips":["Keep the HTTPS path to app.affine.pro free of body-rewriting proxies.","Monitor upstream license API availability from the server host.","Log the raw response body in dev when a malformed-response 500 appears."],"tags":["license","remote-api","upstream","internal-server-error"],"backgroundTag":"malformed-upstream-response","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}