toeverything/AFFiNE · error · InvalidEmail

invalid_email

invalid_email

Error message

An invalid email provided: ${email}

What it means

When config.auth.requireEmailDomainVerification is enabled, assertSignupAllowed additionally calls verifyEmailDomainRecords(email), which checks the email domain's DNS records. Failure throws InvalidEmail (invalid_email, 'An invalid email provided'). Only new (unknown) users reach this check - existing users skip it.

Solutions

  1. Fix the domain's DNS records (MX/verification TXT) as required by your instance's domain verification setup
  2. Use an email address on an already-verified domain
  3. Wait for DNS propagation and retry with a fresh request
  4. Admins: disable requireEmailDomainVerification if the check is not needed for your deployment
Defensive patterns

Strategy: validation

Validate before calling

async function isEmailDomainReady(email: string): Promise<boolean> {
  const domain = email.split('@')[1];
  try {
    const mx = await dns.resolveMx(domain);
    return mx.length > 0;
  } catch {
    return false;
}
}

Try / catch

try {
  await sendMagicLink(email);
} catch (e) {
  if (isAffineErrorCode(e, 'invalid_email')) {
    show('Your email domain is not verified for this workspace. Use a verified domain.');
  } else throw e;
}

Prevention

When it happens

Trigger: Signing up from a domain without the required MX/TXT records AFFiNE expects; DNS not yet propagated after domain setup; typo'd domain (example.co vs example.com); corporate domains with restrictive or missing MX records; resolvers returning SERVFAIL.

Common situations: Self-hosted instances that turned on domain verification; newly purchased domains; internal-only domains without public DNS; verifying from a network with filtered DNS.

Related errors


AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18). Data as JSON: /api/errors/7efb7cd71059529f. Report an issue: GitHub.

Appendix: source

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

      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 b4c8548c09)