toeverything/AFFiNE · error · Error
selfhost license key is required
Error message
selfhost license key is required
What it means
Plain Error thrown during self-host license resolution when both resolved.subjectId and input.licenseKey are absent. resolveEntitlementV1 only returns a subjectId from a valid signed payload; if the license is invalid/missing AND no fallback licenseKey was supplied, there's nothing to key the entitlement row on. This is a generic Error (would surface as 500) — a candidate for promotion to BadRequest.
Source
Thrown at packages/backend/server/src/core/entitlement/service.ts:309
input: SelfhostLicenseEntitlementInput,
options: { emit?: boolean } = {}
) {
const emit = options.emit ?? true;
const resolved = input.license
? resolveEntitlementV1({
deploymentType: 'selfhosted',
targetType: 'workspace',
targetId: input.workspaceId,
signedPayload: input.license,
publicKey: this.crypto.AFFiNEProPublicKey?.toString(),
licenseAesKey: this.crypto.AFFiNEProLicenseAESKey?.toString('hex'),
now: new Date().toISOString(),
})
: null;
const valid = resolved?.valid === true;
const subjectId = resolved?.subjectId ?? input.licenseKey;
if (!subjectId) {
throw new Error('selfhost license key is required');
}
const entitlement = await this.findBySubject('selfhost_license', subjectId);
const data = {
targetType: 'workspace',
targetId: input.workspaceId,
source: 'selfhost_license',
plan: 'selfhost_team',
status: valid ? 'active' : ('needs_reupload' as EntitlementStatus),
subjectId,
quantity: valid ? resolved.quantity : undefined,
signedPayload: input.license ?? undefined,
metadata: {
recurring: resolved?.recurring ?? input.recurring,
validateKey: input.validateKey ?? '',
variant: input.variant ?? null,
errorCode: resolved?.errorCode ?? (valid ? null : 'needs_reupload'),
errorMessage:View on GitHub (pinned to 26c515e050)
Solutions
- On the client, require either a non-empty licenseKey or a valid license file before submitting; validate file shape (JSON, expected envelope) before upload.
- In the service, throw BadRequest('license or licenseKey is required') instead of a plain Error so it returns 400.
- Verify the AFFiNEProPublicKey / AFFiNEProLicenseAESKey env vars are set on the server — without them resolution always returns invalid.
- If a license was working and stopped, check key rotation / clock skew (the `now` used for validation).
Example fix
// before
const subjectId = resolved?.subjectId ?? input.licenseKey;
if (!subjectId) {
throw new Error('selfhost license key is required');
}
// after
const subjectId = resolved?.subjectId ?? input.licenseKey;
if (!subjectId) {
throw new BadRequest('A valid signed license or a licenseKey is required.');
} Defensive patterns
Strategy: validation
Validate before calling
function assertLicenseInput(input: { license?: unknown; licenseKey?: string }) {
if (!input.license && !input.licenseKey) {
throw new UserError('Provide a signed license or a licenseKey');
}
} Type guard
function isSelfHostLicenseKeyRequired(e: unknown): boolean {
return e instanceof Error && e.message === 'selfhost license key is required';
} Try / catch
try {
await entitlement.upsertSelfHostLicense(input);
} catch (e) {
if (isSelfHostLicenseKeyRequired(e)) {
return res.status(400).send('License or licenseKey required');
}
throw e;
} Prevention
- Require a non-empty license or licenseKey in the form before submit.
- Ensure AFFiNEProPublicKey / AFFiNEProLicenseAESKey are configured.
- Validate the license envelope shape (JSON, expected fields) client-side.
When it happens
Trigger: License upload mutation invoked with neither a parseable signed license nor a licenseKey string. The signed payload is malformed/unsigned so resolved is null/invalid, and licenseKey was omitted.
Common situations: User pasted a truncated or wrong-format license. License was generated for a different deployment (publicKey mismatch) so resolution returns invalid with no subjectId. Frontend only sends one of the two fields due to a form bug.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/3923ef53f007fe86.
Report an issue: GitHub.