{"record":{"id":"cb9202f703e7deec","repo":"can1357/oh-my-pi","slug":"multiple-oauth-accounts-are-available-for-provid","errorCode":null,"errorMessage":"Multiple OAuth accounts are available for ${provider}; supply credentialId to pin one exact account","messagePattern":"Multiple OAuth accounts are available for (.+?); supply credentialId to pin one exact account","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/security/auth.ts","lineNumber":49,"sourceCode":"}\n\nexport function selectSecurityAccount(\n\tauthStorage: AuthStorage,\n\tprovider: string,\n\trequestedCredentialId?: number,\n\tsessionId?: string,\n): SecurityAccountRef {\n\tconst accounts = authStorage.listOAuthAccounts(provider, sessionId);\n\tconst selected =\n\t\trequestedCredentialId !== undefined\n\t\t\t? accounts.find(account => account.credentialId === requestedCredentialId)\n\t\t\t: (accounts.find(account => account.active) ?? (accounts.length === 1 ? accounts[0] : undefined));\n\tif (!selected) {\n\t\tif (accounts.length === 0) throw new Error(`Security scans require a stored OAuth account for ${provider}`);\n\t\tif (requestedCredentialId !== undefined) {\n\t\t\tthrow new Error(`Security OAuth credential ${requestedCredentialId} is not available for ${provider}`);\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Multiple OAuth accounts are available for ${provider}; supply credentialId to pin one exact account`,\n\t\t);\n\t}\n\tconst account: SecurityAccountRef = { provider, credentialId: selected.credentialId };\n\tif (selected.accountId !== undefined) account.accountId = selected.accountId;\n\tif (selected.email !== undefined) account.email = selected.email;\n\tif (selected.orgId !== undefined) account.organizationId = selected.orgId;\n\tif (selected.orgName !== undefined) account.organizationName = selected.orgName;\n\treturn account;\n}\n\nexport async function resolveExactSecurityOAuthAccess(\n\tauthStorage: AuthStorage,\n\taccount: SecurityAccountRef,\n\toptions: { forceRefresh: boolean; signal?: AbortSignal },\n): Promise<Extract<OAuthAccessResolution, { ok: true }>> {\n\tconst resolution = await authStorage.getOAuthAccessByCredentialId(account.provider, account.credentialId, options);\n\tif (!resolution) throw new Error(\"The pinned security OAuth credential is unavailable\");","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/security/auth.ts#L31-L67","documentation":"selectSecurityAccount() refuses to guess which stored OAuth account to use when a provider has more than one credential and none is marked active and no credentialId was supplied. The library requires an exact, unambiguous account reference before running security scans. This prevents scans from authenticating as the wrong identity.","triggerScenarios":"Calling security-scan flows (via selectSecurityAccount) for a provider that has 2+ stored OAuth credentials in AuthStorage, with no active flag set and no requestedCredentialId. Passing a credentialId only avoids this if it matches; otherwise the 'not available' variant throws instead.","commonSituations":"Developers who re-logged into the same provider (e.g. ChatGPT/openai-codex) twice, creating duplicate credentials; accounts synced from multiple machines; a previously-active credential lost its active flag after re-auth.","solutions":["Pass an explicit credentialId option to pin the account you want","Mark one stored account as active in AuthStorage","Remove stale/duplicate OAuth credentials for the provider so only one remains","List stored credentials (auth storage contents) to find the correct credentialId"],"exampleFix":"// before\nconst account = selectSecurityAccount(authStorage, provider, undefined);\n// after\nconst account = selectSecurityAccount(authStorage, provider, \"cred_abc123\");","handlingStrategy":"validation","validationCode":"const accounts = authStorage.listOAuthAccounts(provider);\nif (accounts.length > 1 && !accounts.some(a => a.active) && !credentialId) {\n  throw new Error(`Pick one of ${accounts.length} ${provider} credentials: ${accounts.map(a => a.credentialId).join(\", \")}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const account = selectSecurityAccount(authStorage, provider, credentialId);\n} catch (err) {\n  if (err.message.includes(\"Multiple OAuth accounts\")) {\n    // prompt user to choose / pass credentialId\n  } else throw err;\n}","preventionTips":["Always pass an explicit credentialId in automated/headless runs","Keep exactly one credential per provider","Mark the intended default account as active"],"tags":["oauth","authentication","configuration"],"backgroundTag":"ambiguous-oauth-account","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}