coleam00/Archon · warning · APIError

This email is not on the invite allowlist.

Error message

This email is not on the invite allowlist.

What it means

Thrown from the signup createUser hook when the instance is in 'allowlist' (invite-only) signup mode and the registering user's email is not in the configured allowed-emails list. `isEmailAllowed()` returns true for an empty allowlist, so this only fires when an allowlist is actually configured. The APIError('FORBIDDEN') produces a clean 403 for the client instead of a generic 500.

Source

Thrown at packages/server/src/auth/instance.ts:126

            user: User & Record<string, unknown>
          ): Promise<{ data: User & Record<string, unknown> }> => {
            // Defense in depth: `disableSignUp` (set above from getSignupMode)
            // already blocks registration in `disabled` mode before this hook
            // runs — re-check here so the hook stays correct on its own if that
            // upstream enforcement ever changes.
            if (signupDisabled) {
              throw new APIError('FORBIDDEN', { message: 'Signup is disabled.' });
            }
            // Invite gate (`allowlist` mode): reject signups whose email is not on
            // the allowlist. Throwing APIError surfaces a clean 403 instead of a
            // generic 500. An empty allowlist makes isEmailAllowed() return true,
            // so this hook is a no-op in `open` mode — `disableSignUp` and the
            // posture above are what actually govern whether signup is permitted.
            if (!user.email) {
              throw new APIError('BAD_REQUEST', { message: 'Email is required.' });
            }
            if (!isEmailAllowed(user.email, allowedEmails)) {
              throw new APIError('FORBIDDEN', {
                message: 'This email is not on the invite allowlist.',
              });
            }
            return { data: user };
          },
        },
      },
    },
  });
}

/**
 * Release the Better Auth pg.Pool on graceful shutdown. No-op when web auth is
 * disabled (no pool was ever created).
 */
export async function closeAuth(): Promise<void> {
  if (authPool) {
    await authPool.end();

View on GitHub (pinned to 0773b97458)

Solutions

  1. Ask the operator to add the user's email (or their email domain) to the allowlist configuration and restart/reload.
  2. Verify the allowlist value matches exactly what the identity provider returns (case, plus-tags, alias vs primary address).
  3. If the instance should be open to everyone, switch signup mode from 'allowlist' to 'open'.
  4. Check server logs to confirm which email was evaluated against the allowlist to spot mismatches.

Example fix

// before
ALLOWED_EMAILS=alice@example.com
// after: include the user or their domain
ALLOWED_EMAILS=alice@example.com,bob@example.com,@example.com
Defensive patterns

Strategy: validation

Validate before calling

// client-side pre-check when the instance exposes its mode
const { mode, allowedEmails } = await (await fetch('/api/get-signup-mode')).json();
if (mode === 'allowlist' && allowedEmails?.length && !allowedEmails.includes(email)) {
  showNotice('This email is not on the invite list.');
  return;
}

Try / catch

try {
  await authClient.signUp.email({ email, password, name });
} catch (e) {
  if (e?.status === 403 && /invite allowlist/i.test(e?.message ?? '')) {
    showNotice('Your email is not invited. Ask an admin to add it.');
  } else throw e;
}

Prevention

When it happens

Trigger: Signup mode is 'allowlist', ALLOWED_EMAILS (or equivalent) is non-empty, and a user attempts registration with an email that does not match any allowlist entry (exact or domain match per isEmailAllowed).

Common situations: A user with the wrong personal email tries to join a company instance; an admin typo'd the address in the allowlist; the allowlist uses full addresses while the user signs up with an alias; emails differ in case or plus-addressing and the matcher doesn't normalize them.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/afc178fa545ff1de. Report an issue: GitHub.