{"record":{"id":"be48795865d3132c","repo":"nextauthjs/next-auth","slug":"missing-or-invalid-provider-account","errorCode":null,"errorMessage":"Missing or invalid provider account","messagePattern":"Missing or invalid provider account","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/lib/actions/callback/handle-login.ts","lineNumber":34,"sourceCode":" * linking (or not linking) accounts depending on if the user is currently logged\n * in, if they have account already and the authentication mechanism they are using.\n *\n * It prevents insecure behaviour, such as linking OAuth accounts unless a user is\n * signed in and authenticated with an existing valid account.\n *\n * All verification (e.g. OAuth flows or email address verification flows) are\n * done prior to this handler being called to avoid additional complexity in this\n * handler.\n */\nexport async function handleLoginOrRegister(\n  sessionToken: SessionToken,\n  _profile: User | AdapterUser | { email: string },\n  _account: AdapterAccount | Account | null,\n  options: InternalOptions\n) {\n  // Input validation\n  if (!_account?.providerAccountId || !_account.type)\n    throw new Error(\"Missing or invalid provider account\")\n  if (![\"email\", \"oauth\", \"oidc\", \"webauthn\"].includes(_account.type))\n    throw new Error(\"Provider not supported\")\n\n  const {\n    adapter,\n    jwt,\n    events,\n    session: { strategy: sessionStrategy, generateSessionToken },\n  } = options\n\n  // If no adapter is configured then we don't have a database and cannot\n  // persist data; in this mode we just return a dummy session object.\n  if (!adapter) {\n    return { user: _profile as User, account: _account as Account }\n  }\n\n  const profile = _profile as AdapterUser\n  let account = _account as AdapterAccount","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/actions/callback/handle-login.ts#L16-L52","documentation":"During the OAuth/email callback, handleLoginOrRegister validates the provider account object returned by the provider before linking or creating a user. If the account has no providerAccountId or no type, the flow cannot identify the account and throws this Error in packages/core/src/lib/actions/callback/handle-login.ts:34.","triggerScenarios":"A custom OAuth provider whose profile/account callback omits providerAccountId or type; a custom credentials-like flow that returns null or a malformed account to signIn; a provider returning an account object missing required AdapterAccount fields.","commonSituations":"Writing a custom OAuthProvider and forgetting to set providerAccountId in the account returned from the tokenset/profile step; using an older provider package that returns a different account shape; mis-wrapping a custom flow to call the internal callback action.","solutions":["In your custom provider, always return an account with providerAccountId and type (e.g. 'oauth') from the getUserFromTokenset/profile callback.","Check that the provider's token endpoint response actually contains an account identifier (sub / id) and map it to providerAccountId.","Update @auth/core and the provider package to compatible versions so account normalization runs."],"exampleFix":"// before (custom provider)\nreturn { tokens: tokenset }\n// after\nreturn { token: tokenset, account: { providerAccountId: profile.sub, type: 'oauth', provider: 'myprovider' } }","handlingStrategy":"validation","validationCode":"if (!account?.providerAccountId || !account?.type) {\n  throw new Error('Custom provider returned an incomplete account')\n}","typeGuard":"function isValidAccount(a: any): a is AdapterAccount {\n  return !!a && typeof a.providerAccountId === 'string' && a.providerAccountId.length > 0 && typeof a.type === 'string' && ['email','oauth','oidc','webauthn'].includes(a.type)\n}","tryCatchPattern":"try {\n  await signIn('myprovider', ...)\n} catch (e) {\n  if ((e as Error).message === 'Missing or invalid provider account') {\n    // inspect the custom provider's account mapping\n  }\n}","preventionTips":["In custom providers, always map profile.sub (or equivalent) to providerAccountId.","Type the account as AdapterAccount so TypeScript enforces required fields.","Log the account object during development to verify its shape before production."],"tags":["oauth","provider","validation","callback"],"backgroundTag":"invalid-provider-account","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}