{"record":{"id":"d3248c64ba02bcc5","repo":"benweet/stackedit","slug":"github-account-id-not-expected","errorCode":null,"errorMessage":"GitHub account ID not expected.","messagePattern":"GitHub account ID not expected\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/services/providers/helpers/githubHelper.js","lineNumber":104,"sourceCode":"    })).body;\n\n    // Call the user info endpoint\n    const user = (await networkSvc.request({\n      method: 'GET',\n      url: 'https://api.github.com/user',\n      headers: {\n        Authorization: `token ${accessToken}`,\n      },\n    })).body;\n    userSvc.addUserInfo({\n      id: `${subPrefix}:${user.id}`,\n      name: user.login,\n      imageUrl: user.avatar_url || '',\n    });\n\n    // Check the returned sub consistency\n    if (sub && `${user.id}` !== sub) {\n      throw new Error('GitHub account ID not expected.');\n    }\n\n    // Build token object including scopes and sub\n    const token = {\n      scopes,\n      accessToken,\n      name: user.login,\n      sub: `${user.id}`,\n      repoFullAccess: scopes.includes('repo'),\n    };\n\n    // Add token to github tokens\n    store.dispatch('data/addGithubToken', token);\n    return token;\n  },\n  async addAccount(repoFullAccess = false) {\n    const token = await this.startOauth2(getScopes({ repoFullAccess }));\n    badgeSvc.addBadge('addGitHubAccount');","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/benweet/stackedit/blob/6dce2a5e36b755a0c244522b48a06c91a2df0f59/src/services/providers/helpers/githubHelper.js#L86-L122","documentation":"After a GitHub OAuth2 exchange, startOauth2 compares the authenticated user's id with the `sub` claim of the app token. If `${user.id}` !== sub, githubHelper throws at src/services/providers/helpers/githubHelper.js:104 because the GitHub account that authorized the app differs from the identity the token was minted for. This guards against binding workspace data to the wrong GitHub identity.","triggerScenarios":"`${user.id}` !== sub in startOauth2: user authorized with a different GitHub account than the one associated with the token's sub; stale sub from a previously saved token reused in a new flow; multiple GitHub accounts in the browser.","commonSituations":"Developers with personal and work GitHub accounts switching between them; re-auth after account migration/renaming with cached tokens; shared-machine browser sessions.","solutions":["Reconnect the provider while logged into the intended GitHub account (use a private window if multiple accounts are signed in).","Clear the saved GitHub token and restart the OAuth flow so sub is derived from the fresh exchange.","Verify the sub value fed into the token construction matches the account that completed authorization.","Check the token's stored sub in app storage and remove mismatches before retrying."],"exampleFix":"// before\nif (sub && `${user.id}` !== sub) {\n  throw new Error('GitHub account ID not expected.');\n}\n// after\nif (sub && `${user.id}` !== sub) {\n  throw new Error(`GitHub account ID not expected (authorized ${user.id}, expected ${sub}). Sign in with the correct GitHub account.`);\n}","handlingStrategy":"try-catch","validationCode":"function savedGitHubSubMatches(sub) {\n  const saved = readSavedProviderToken('github');\n  return !saved || !saved.sub || saved.sub === sub;\n}","typeGuard":"function isGitHubAccountMismatch(err) {\n  return err instanceof Error && /account ID not expected/i.test(err.message);\n}","tryCatchPattern":"try {\n  await githubHelper.startOauth2(...);\n} catch (err) {\n  if (isGitHubAccountMismatch(err)) {\n    clearStoredTokens('github');\n    promptReauthWithCorrectAccount();\n  }\n}","preventionTips":["Ensure the browser is signed into the intended GitHub account before authorizing.","Drop old tokens when switching between personal and work accounts.","Derive sub from the same OAuth exchange as the access token.","Offer an explicit 'switch account' flow that clears stored tokens first."],"tags":["oauth","github","account-mismatch"],"backgroundTag":"oauth-account-mismatch","analyzedSha":"6dce2a5e36b755a0c244522b48a06c91a2df0f59","analyzedAt":"2026-09-01T00:49:23.866Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}