HeyPuter/puter · error · HttpError

email_confirmation_required

email_confirmation_required

Error message

Please confirm your email to continue

What it means

Raised by `assertVerifiedAccount` when the user row has `requires_email_confirmation` truthy AND `email_confirmed` falsy. The account is gated until the user confirms their email address.

Source

Thrown at src/backend/core/http/middleware/gates.ts:372

 *
 * Throws 403 with a per-gate legacy code (`email_confirmation_required` /
 * `phone_verification_required` / `card_verification_required`) so clients can
 * show the right prompt instead of a generic error. There is no state where a
 * user should be let in with any verification pending, so the first pending
 * gate rejects.
 */
export const assertVerifiedAccount = (
    user:
        | {
              requires_email_confirmation?: unknown;
              email_confirmed?: unknown;
              requires_phone_verification?: unknown;
              requires_card_verification?: unknown;
          }
        | undefined,
): void => {
    if (user?.requires_email_confirmation && !user?.email_confirmed) {
        throw new HttpError(403, 'Please confirm your email to continue', {
            legacyCode: 'email_confirmation_required',
        });
    }
    if (user?.requires_phone_verification) {
        throw new HttpError(
            403,
            'Please verify your phone number to continue',
            {
                legacyCode: 'phone_verification_required' as never,
            },
        );
    }
    if (user?.requires_card_verification) {
        throw new HttpError(403, 'Please verify your card to continue', {
            legacyCode: 'card_verification_required' as never,
        });
    }
};

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Open the confirmation link sent to the account's email.
  2. Trigger a resend-confirmation flow if the link expired.
  3. As admin, set `requires_email_confirmation=false` or `email_confirmed=true` if the gate is misapplied.
  4. Verify the email_confirmed flag actually flipped after confirmation.
Defensive patterns

Strategy: try-catch

Validate before calling

// If the API surfaces the user object, gate the action client-side:
if (user.requires_email_confirmation && !user.email_confirmed) {
  promptEmailConfirmation();
}

Type guard

const needsEmailConfirmation = (u) => !!(u && u.requires_email_confirmation && !u.email_confirmed);

Try / catch

try { await call(); }
catch (e) {
  if (e.code === 'email_confirmation_required') { await resendConfirmation(); return; }
  throw e;
}

Prevention

When it happens

Trigger: A newly registered account that has not clicked the confirmation link hits a route guarded by `assertVerifiedAccount`; or an admin toggled `requires_email_confirmation` on for existing accounts.

Common situations: Confirmation email landed in spam / never opened; the flag was enabled server-side for compliance on a feature the user is trying to reach; user changed email and hasn't re-confirmed.

Related errors


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/3fde8767852408e1. Report an issue: GitHub.