RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-challenge-method
error-invalid-challenge-method
Error message
invalid challenge method
What it means
Thrown by POST twoFactorChallenges.sendEmailCode when the pending challenge's method is anything other than 'email'. sendEmailCode only knows how to send email codes; a challenge created for TOTP or another method cannot be serviced by it. Which method a challenge uses is decided by the user's configured 2FA during the OAuth login flow.
Source
Thrown at apps/meteor/server/api/v1/twoFactorChallenges.ts:34
async post() {
const { challengeId } = this.bodyParams;
if (!challengeId) {
throw new Meteor.Error('error-parameter-required', 'challengeId is required');
}
const challenge = await TwoFactorChallenges.findOneByPendingChallengeId(challengeId);
if (!challenge) {
throw new Meteor.Error('error-challenge-not-found', 'challenge not found');
}
if (challenge.expireAt && challenge.expireAt < new Date()) {
throw new Meteor.Error('error-challenge-expired', 'challenge expired');
}
if (challenge.method !== 'email') {
throw new Meteor.Error('error-invalid-challenge-method', 'invalid challenge method');
}
const { userId } = challenge;
const user = await getUserForCheck(userId);
if (!user) {
throw new Meteor.Error('error-user-not-found', 'user not found');
}
await emailCheckForOAuth.sendEmailCode(user);
return API.v1.success();
},
},
);
API.v1.addRoute(View on GitHub (pinned to b2c16d5842)
Solutions
- Branch on the method reported by the login/challenge response: show the email resend button only for method 'email'
- For TOTP challenges, direct the user to their authenticator app and use twoFactorChallenges.verifyChallenge with the 6-digit code
- Do not call sendEmailCode speculatively to 'detect' the method — inspect the challenge payload instead
Example fix
// before
await sdk.post('twoFactorChallenges.sendEmailCode', { challengeId }); // assumes email
// after
if (challenge.method === 'email') {
await sdk.post('twoFactorChallenges.sendEmailCode', { challengeId });
} else {
showAuthenticatorInput(); // TOTP path
} Defensive patterns
Strategy: try-catch
Validate before calling
if (challenge.method && challenge.method !== 'email') throw new Error(`sendEmailCode only handles email challenges, got ${challenge.method}`); Type guard
const isEmailChallenge = (c: { method?: string }): boolean => c.method === 'email'; Try / catch
catch (e) { if (e?.error === 'error-invalid-challenge-method') renderTotpInput(); else throw e; } Prevention
- Branch UI on challenge.method before choosing which endpoint to call
- Never probe with sendEmailCode to detect the method
When it happens
Trigger: User's 2FA is TOTP and the client unconditionally calls sendEmailCode for every challenge; a hybrid flow where the challenge method is chosen server-side but the client assumes email; calling sendEmailCode with a challengeId obtained from a TOTP-gated OAuth login.
Common situations: Frontends hardcoding the email-code path after testing only against email-2FA accounts; workspaces where admins switched the test user from email codes to authenticator apps; clients not branching on the method field returned with the challenge.
Related errors
- error-parameter-required
- error-challenge-not-found
- error-challenge-expired
- totp-max-attempts
- error-user-not-found
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/327305f0f9cbf04d.
Report an issue: GitHub.