{"record":{"id":"120db0672efc7340","repo":"mastra-ai/mastra","slug":"github-oauth-token-exchange-failed-res-status","errorCode":null,"errorMessage":"GitHub OAuth token exchange failed: ${res.status}","messagePattern":"GitHub OAuth token exchange failed: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/integrations/github/integration.ts","lineNumber":1123,"sourceCode":"    url.searchParams.set('state', state);\n    return url.toString();\n  }\n\n  /** Exchange an OAuth `code` for a user access token. */\n  async exchangeOAuthCode(code: string, redirectUri: string): Promise<string> {\n    const res = await fetch('https://github.com/login/oauth/access_token', {\n      method: 'POST',\n      signal: AbortSignal.timeout(GITHUB_OAUTH_TOKEN_TIMEOUT_MS),\n      headers: { 'content-type': 'application/json', accept: 'application/json' },\n      body: JSON.stringify({\n        client_id: this.#clientId,\n        client_secret: this.#clientSecret,\n        code,\n        redirect_uri: redirectUri,\n      }),\n    });\n    if (!res.ok) {\n      throw new Error(`GitHub OAuth token exchange failed: ${res.status}`);\n    }\n    const data = (await res.json()) as { access_token?: string; error?: string; error_description?: string };\n    if (!data.access_token) {\n      throw new Error(\n        `GitHub OAuth token exchange returned no token: ${data.error_description ?? data.error ?? 'unknown'}`,\n      );\n    }\n    return data.access_token;\n  }\n\n  /**\n   * The integration's HTTP surface: the `/web/github/*` + `/auth/github/*`\n   * Mastra `apiRoutes` (webhook handler, install/OAuth flow, project +\n   * worktree + session operations). The factory folds these into the server's\n   * `apiRoutes` when the feature is ready. Handlers operate on this instance.\n   */\n  routes(ctx: IntegrationContext): ApiRoute[] {\n    this.#storage = ctx.storage;","sourceCodeStart":1105,"sourceCodeEnd":1141,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/integrations/github/integration.ts#L1105-L1141","documentation":"The GitHub OAuth web-application flow token exchange (POST to https://github.com/login/oauth/access_token with client_id, client_secret, code, redirect_uri) returned a non-OK HTTP status; the integration surfaces the status code in this error.","triggerScenarios":"Exchanging an OAuth authorization code for an access token when GitHub responds with 4xx/5xx — most commonly 401 (wrong client_secret), 404 (wrong client_id), or 400 (expired/already-used code or redirect_uri mismatch).","commonSituations":"Mismatched redirect_uri between the authorize step and the token exchange; authorization code reused or older than ~10 minutes; incorrect/misconfigured GITHUB_CLIENT_SECRET; GitHub outage (5xx).","solutions":["Verify clientId and clientSecret match the GitHub OAuth App","Ensure redirect_uri is byte-identical to the one used in the authorize redirect and registered on the app","Re-run the OAuth flow to obtain a fresh authorization code (codes are single-use and short-lived)","Retry the flow after checking the GitHub status page if the status is 5xx"],"exampleFix":"// before\nredirect_uri: 'https://app.example.com/auth/github/callback/' // trailing slash differs from authorize step\n// after\nredirect_uri: 'https://app.example.com/auth/github/callback' // exact match with authorize call","handlingStrategy":"retry","validationCode":"if (!clientId || !clientSecret || !code || redirectUri !== expectedRedirectUri) {\n  throw new Error('OAuth exchange prerequisites invalid');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const token = await gh.exchangeOAuthCode({ code, redirectUri });\n} catch (e) {\n  if (e.message.startsWith('GitHub OAuth token exchange failed:')) {\n    const status = Number(e.message.match(/(\\d+)$/)?.[1]);\n    if (status >= 500) retryWithBackoff();\n    else restartOauthFlow(); // 4xx: code/credentials/redirect_uri problem — do not retry the same code\n  } else throw e;\n}","preventionTips":["Keep redirect_uri identical between the authorize redirect and the token exchange","Never reuse authorization codes; always start a fresh OAuth flow on failure","Verify client credentials against the GitHub OAuth App settings before deploying","Check the GitHub status page for 5xx-caused failures before debugging app config"],"tags":["github","oauth","network","http"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}