{"record":{"id":"259040e0465155fc","repo":"coleam00/Archon","slug":"login-attempt-was-superseded-by-a-newer-one-retry","errorCode":null,"errorMessage":"Login attempt was superseded by a newer one. Retry to start a fresh login.","messagePattern":"Login attempt was superseded by a newer one\\. Retry to start a fresh login\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/core/src/credentials/oauth-bridge.ts","lineNumber":396,"sourceCode":"    sessions.delete(sessionId);\n    if (session.portBusy) {\n      // Retryable: the cancel above releases the port as soon as the previous\n      // login unwinds (microtasks for pi flows), so \"retry shortly\" is honest\n      // advice — and a restart always clears it (#1963).\n      throw new OAuthCallbackPortBusyError(\n        `A previous '${provider}' login attempt is still holding the OAuth callback port. ` +\n          'Wait a few seconds and retry; if it persists, restart the Archon server.'\n      );\n    }\n    throw new Error(session.detail ?? 'Subscription login failed to start.');\n  }\n\n  // Superseded (or cancelled) while still waiting for the first signal — the\n  // session is already gone from the map, so a 200 here would hand back a\n  // url-less session the first poll immediately reports as \"not found\".\n  // Throw the honest answer instead (S4).\n  if (!sessions.has(sessionId)) {\n    throw new Error('Login attempt was superseded by a newer one. Retry to start a fresh login.');\n  }\n\n  return {\n    sessionId,\n    mode: externalMode(session),\n    url: session.url,\n    userCode: session.userCode,\n    verificationUri: session.verificationUri,\n    expiresIn: Math.round(SESSION_TTL_MS / 1000),\n  };\n}\n\n/**\n * Poll a login session. For manual-code flows, pass the user's pasted `code`\n * (once) to unblock `login()`. Returns `connected` (and clears the session) on\n * success, `error` on failure/expiry, else `pending`.\n */\nexport function pollOAuth(sessionId: string, userId: string, code?: string): PollOAuthResult {","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/core/src/credentials/oauth-bridge.ts#L378-L414","documentation":"Thrown by startOAuth (oauth-bridge.ts:396) when, while waiting for the first auth signal, the session it just created disappears from the sessions map — i.e. it was superseded by a newer startOAuth for the same user/vendor or cancelled. Rather than returning a 200 with a url-less session that would immediately report 'not found' on the first poll, the bridge throws this honest error.","triggerScenarios":"Two startOAuth calls racing for the same userId (or same callback-server vendor): the older call's session is aborted and deleted by the newer call, and when the older call wakes from its firstSignal race it finds sessions.has(sessionId) === false. Also triggered by cancelOAuth or the expiry sweep landing in that window.","commonSituations":"A user double-clicking 'Login' in the web UI; a CLI retry fired while the previous attempt is still initializing; automated callers retrying startOAuth without cancelling the previous attempt.","solutions":["Simply retry startOAuth once — the newest attempt wins and will proceed normally.","Serialize login attempts client-side: disable the login button / use a mutex while one is in flight.","Cancel the prior attempt explicitly (cancelOAuth) before starting a new one.","Treat this error as benign/superseded in callers, not a hard failure."],"exampleFix":"// before\nawait Promise.all([startOAuth(user, 'anthropic'), startOAuth(user, 'anthropic')]);\n// after\nconst result = await loginMutex.runExclusive(() => startOAuth(user, 'anthropic'));","handlingStrategy":"try-catch","validationCode":"// Guard: do not issue a concurrent start for the same user/provider\nif (pendingLoginByUser.has(userId)) {\n  return pendingLoginByUser.get(userId)!; // reuse the in-flight promise\n}","typeGuard":null,"tryCatchPattern":"try {\n  const result = await startOAuth(userId, providerId);\n  return result;\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Login attempt was superseded')) {\n    return startOAuth(userId, providerId); // retry once; newest attempt wins\n  }\n  throw e;\n}","preventionTips":["Debounce/disable the login button while a login is initializing.","Serialize startOAuth calls per user with a mutex or in-flight promise map.","Treat supersession as a normal, retryable outcome — not a bug report.","Avoid background health-check callers that re-trigger startOAuth for an active login."],"tags":["oauth","race-condition","superseded"],"backgroundTag":"request-superseded","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}