sahat/hackathon-starter · error · Error
PROVIDER_COLLISION
PROVIDER_COLLISION
Error message
PROVIDER_COLLISION
What it means
Thrown by handleAuthLogin when a logged-in user attempts to link an OAuth provider account that is already linked to a different local user. The code looks up a User whose provider field equals the provider profile id and compares it to req.user.id; a mismatch means the provider identity belongs to someone else.
Source
Thrown at config/passport.js:84
* - Check if it's a returning user.
* - If returning user, sign in and we are done.
* - Else check if there is an existing account with user's email.
* - If there is, return an error message.
* - Else create a new account.
*/
/**
* Helper function that contains the shared post-profile OAuth logic
* (supports OAuth 1.0a and OAuth 2.0 providers).
* Returns User (new or updated) on success or throws Error on failure.
*/
async function handleAuthLogin(req, accessToken, refreshToken, providerName, params, providerProfile, sessionAlreadyLoggedIn, tokenSecret, oauth2provider, tokenConfig = {}, refreshTokenExpiration = null) {
if (sessionAlreadyLoggedIn) {
const existingUser = await User.findOne({
[providerName]: { $eq: providerProfile.id },
});
if (existingUser && existingUser.id !== req.user.id) {
throw new Error('PROVIDER_COLLISION');
}
let user;
if (oauth2provider) {
user = await saveOAuth2UserTokens(req, accessToken, refreshToken, params.expires_in, refreshTokenExpiration, providerName, tokenConfig);
} else {
user = await User.findById(req.user.id);
user.tokens.push({ kind: providerName, accessToken, ...(tokenSecret && { tokenSecret }) });
}
user[providerName] = providerProfile.id;
user.profile.name = user.profile.name || providerProfile.name;
user.profile.gender = user.profile.gender || providerProfile.gender;
if (providerProfile.picture) {
if (!user.profile.pictures || user.profile.pictureSource === undefined) {
// legacy account (pre-multi-picture support)
user.profile.pictures = new Map();
user.profile.picture = providerProfile.picture;
user.profile.pictureSource = providerName;View on GitHub (pinned to c12e339564)
Solutions
- Log in with the provider account directly instead of linking it, or link the provider from the account that actually owns it
- If the provider identity is stale, unlink it from the other account first via /account/unlink/:provider
- Inspect the User collection for duplicate provider ids and consolidate accounts manually (mongodb shell)
Example fix
// before: logged in as A, trying to link provider owned by B
// after: check ownership before linking
const owner = await User.findOne({ [provider]: profile.id });
if (owner && owner.id !== req.user.id) {
req.flash('errors', { msg: 'That account is already linked to another user.' });
return res.redirect('/account');
} Defensive patterns
Strategy: validation
Validate before calling
const owner = await User.findOne({ [provider]: providerProfile.id });
if (owner && owner.id !== currentUser.id) {
// block linking, show explanatory flash message
} Try / catch
catch (e) { if (e.message === 'PROVIDER_COLLISION') { req.flash('errors', {msg:'That account belongs to another user'}); return res.redirect('/account'); } throw e; } Prevention
- Show linked-provider ownership on the profile page before linking
- Educate users that one provider identity maps to exactly one local account
When it happens
Trigger: User A is logged in and visits /auth/<provider> (account-linking flow) while the provider account (e.g. a Google id) is already stored on User B's document; User.findOne({[providerName]: providerProfile.id}) returns B, whose id !== req.user.id.
Common situations: Two team members sharing one OAuth account (shared Twitter/Facebook login), a user who previously created a separate account with the same provider identity, or testing account linking while logged in as a different user.
Related errors
- EMAIL_REQUIRED
- EMAIL_COLLISION
- Missing or invalid token/tokenSecret
- HTTP error! status: ${response.status}
AI-assisted analysis of sahat/hackathon-starter@c12e339564 (2026-08-27).
Data as JSON: /api/errors/44e3ef1d1ec7e7db.
Report an issue: GitHub.