toeverything/AFFiNE · error · SignUpForbidden

sign_up_forbidden

sign_up_forbidden

Error message

You are not allowed to sign up.

What it means

In assertSignupAllowed (reached from send when no existing user matches the email), if config.auth.allowSignup is false the server throws SignUpForbidden. This is the global signup toggle: when off, brand-new emails cannot initiate a magic-link sign-in because account creation is disabled. Existing users are unaffected (they never reach this branch).

Source

Thrown at packages/backend/server/src/core/auth/magic-link.ts:135

      TokenType.SignIn,
      consumed.token,
      {
        credential: email,
      }
    );

    if (!tokenRecord) {
      throw new InvalidEmailToken();
    }

    const user = await this.models.user.fulfill(email);

    return { userId: user.id, method: 'magic_link' };
  }

  private async assertSignupAllowed(email: string) {
    if (!this.config.auth.allowSignup) {
      throw new SignUpForbidden();
    }

    if (!this.config.auth.requireEmailDomainVerification) {
      return;
    }

    if (!(await verifyEmailDomainRecords(email))) {
      throw new InvalidEmail({ email });
    }
  }
}

View on GitHub (pinned to 26c515e050)

Solutions

  1. Set config.auth.allowSignup=true (AFFiNE_AUTH_ALLOW_SIGNUP=true) and redeploy if self-registration is desired.
  2. Provision the user account through admin tooling / invitation instead of self-signup.
  3. Sign in with an existing account rather than attempting to register a new email.
  4. Confirm the email is not typo'd — an existing user with a slightly different email won't match.

Example fix

# enable self-signup
AFFiNE_AUTH_ALLOW_SIGNUP=true
Defensive patterns

Strategy: validation

Type guard

function isSignUpForbidden(err: unknown): boolean {
  return (
    !!err &&
    typeof err === 'object' &&
    (err as { code?: string }).code === 'sign_up_forbidden'
  );
}

Try / catch

try {
  await magicLink.send(email);
} catch (err) {
  if (isSignUpForbidden(err)) {
    showUser('Sign-up is disabled. Contact your administrator.');
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: config.auth.allowSignup === false AND the email has no user row AND send() is called. Typical of self-hosted deployments that disable open registration.

Common situations: Self-hosted admin set AFFiNE_AUTH_ALLOW_SIGNUP=false (or omitted enabling it). A private deployment where accounts are provisioned out-of-band. Someone tries to self-register on an invite-only instance.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/95dcf65d41d3ae56. Report an issue: GitHub.