{"record":{"id":"5e1027b813e800a5","repo":"toeverything/AFFiNE","slug":"invalid-license-to-activate","errorCode":"invalid_license_to_activate","errorMessage":"Invalid license to activate. Invalid license.","messagePattern":"Invalid license to activate\\. Invalid license\\.","errorType":"exception","errorClass":"InvalidLicenseToActivate","httpStatus":400,"severity":"error","filePath":"packages/backend/server/src/plugins/license/service.ts","lineNumber":169,"sourceCode":"      expiresAt: this.licenseExpiresAt(resolved),\n      validatedAt,\n      variant: SubscriptionVariant.Onetime,\n      license,\n    });\n    await this.event.emitAsync('workspace.subscription.activated', {\n      workspaceId,\n      plan: SubscriptionPlan.SelfHostedTeam,\n      recurring: this.licenseRecurring(resolved),\n      quantity: this.licenseQuantity(resolved),\n    });\n\n    return installed;\n  }\n\n  previewLicense(license: Buffer): LicensePreview {\n    const resolved = this.resolveWorkspaceTeamLicense(null, license);\n    if (!resolved.valid) {\n      throw new InvalidLicenseToActivate({\n        reason: 'Invalid license.',\n      });\n    }\n    const expiresAt = this.licenseExpiresAt(resolved);\n\n    return {\n      id: this.licenseSubjectId(resolved),\n      workspaceId: this.licenseWorkspaceId(resolved),\n      plan: SubscriptionPlan.SelfHostedTeam,\n      recurring: this.licenseRecurring(resolved),\n      quantity: this.licenseQuantity(resolved),\n      issuedAt: new Date(resolved.issuedAt ?? ''),\n      expiresAt,\n      endAt: expiresAt,\n      entity: resolved.entity ?? '',\n      issuer: resolved.issuer ?? '',\n      valid: true,\n    };","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/plugins/license/service.ts#L151-L187","documentation":"previewLicense() resolves an uploaded license buffer without persisting it, to show the admin what would be installed. It throws InvalidLicenseToActivate with reason 'Invalid license.' when the resolver reports an invalid entitlement — i.e. signature/structure verification failed rather than a clean expiry or workspace mismatch, which have their own dedicated throws inside resolveWorkspaceTeamLicense. This branch is the defensive catch-all of the preview flow.","triggerScenarios":"Calling previewLicense(licenseBuffer) with a truncated download, a file that is not an AFFiNE Pro license at all (e.g. an EULA PDF or JSON), a license signed for a different key scheme, or bytes corrupted in transit/base64 decoding.","commonSituations":"Admin uploads the wrong file from the license email; CI tests feed arbitrary buffers; license file edited by hand or re-saved with encoding changes (BOM, CRLF); browser 'save page' instead of raw download.","solutions":["Re-download the license file from https://app.affine.pro and upload it unmodified.","Confirm you are uploading the binary license (usually .license file), not the order confirmation or invoice.","Verify checksum/size against the source if corruption is suspected; if it still fails, the file may be for a different product line — request a reissue from Affine support."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const LICENSE_MAGIC = 0x41; // inspect first bytes / expected file shape before upload\nfunction looksLikeLicenseFile(buf: Buffer): boolean {\n  return buf.length > 0 && buf.length < 1_000_000; // reject obvious wrong files (PDF/HTML)\n}","typeGuard":"function isInvalidLicenseToActivate(e: unknown): e is InvalidLicenseToActivate {\n  return e instanceof InvalidLicenseToActivate;\n}","tryCatchPattern":"try {\n  const preview = licenseService.previewLicense(licenseBuffer);\n} catch (e) {\n  if (e instanceof InvalidLicenseToActivate) {\n    // surface e.extensions.reason to the uploader ('Invalid license.' → re-download the file)\n  } else throw e;\n}","preventionTips":["Accept only the original downloaded .license file; verify size/type before upload.","Avoid manual edits/re-saves of license files (encoding changes break signatures).","Preview licenses in a dry-run step so bad files fail before hitting install flows."],"tags":["license","self-hosted","signature-verification","upload"],"backgroundTag":"license-validation-failed","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"}