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
- Open the confirmation link sent to the account's email.
- Trigger a resend-confirmation flow if the link expired.
- As admin, set `requires_email_confirmation=false` or `email_confirmed=true` if the gate is misapplied.
- 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
- Confirm email immediately after signup.
- Resend confirmation if the link may have expired.
- Surface the unconfirmed state in the UI before the gated action.
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
- phone_verification_required
- card_verification_required
- account_is_not_verified
- account_suspended
- user_not_found
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/3fde8767852408e1.
Report an issue: GitHub.