{"version":"2.1.206","anchor":"oauth-token-expiry-error","canonical_anchor":"oauth-token-expiry-error","heading":"OAuth Token Expiry Error","tier":null,"area":null,"scope":null,"heads_up":null,"url":"https:\/\/changelogs.core-directive.com\/v\/2.1.206\/e\/oauth-token-expiry-error","release_url":"https:\/\/changelogs.core-directive.com\/v\/2.1.206","markdown":"### OAuth Token Expiry Error\n\n**What**\n\nExpired OAuth refresh tokens now throw a distinct `OAuthRefreshDeadError` with a clear message, rather than a generic error.\n\n**Details**\n\n- Message: \"OAuth refresh token is no longer valid; run \/login to re-authenticate\"\n- The error class name `\"OAuthRefreshDeadError\"` is surfaced in logs and can be caught specifically by error handlers.\n- The error is thrown at API client construction time when all three conditions hold: no API key is available, no current OAuth access token exists, and `OGt()` is true \u2014 meaning the stored OAuth refresh token is either an empty string `\"\"` or is found in an in-memory dead-token blacklist set (populated whenever a token refresh request fails).\n- When this error propagates to the request error handler, the displayed UI message branches by session type: interactive REPL sessions show `\"Login expired \u00b7 Please run \/login\"`; agent\/non-interactive sessions show `\"Failed to authenticate: OAuth session expired and could not be refreshed\"`.\n- The error condition is also checked in the first-party HTTP client's teleport-org auth path: after a forced token refresh attempt, if `OGt()` is still true, the request returns `{ ok: false, reason: \"no-auth\" }` with the same detail message rather than throwing.\n- Previously, token expiry produced ambiguous error messages that did not distinguish between a missing token and a definitively-expired one.\n\n**Evidence**\n\nError class (search for `\"OAuthRefreshDeadError\"`); dead-token check (search for `\"OGt()\"`); UI message branching (search for `\"Login expired\"` alongside `\"OAuthRefreshDeadError\"`)"}