{"record":{"id":"d15d9d6e4483d6f7","repo":"can1357/oh-my-pi","slug":"oauth-authorization-code-is-invalid-or-expired-pl","errorCode":null,"errorMessage":"OAuth authorization code is invalid or expired. Please try again.","messagePattern":"OAuth authorization code is invalid or expired\\. Please try again\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/modes/controllers/mcp-command-controller.ts","lineNumber":1036,"sourceCode":"\t\t\t\tresource: flow.resource,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\t// Esc, an external abort, or a newer MCP flow are neutral\n\t\t\t// cancellations. The timeout path also aborts the controller but does\n\t\t\t// not set this flag, so it remains a surfaced error.\n\t\t\tif (cancellationRequested) {\n\t\t\t\tthrow new MCPOAuthCancelledError();\n\t\t\t}\n\n\t\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\n\t\t\t// Provide helpful error messages based on failure type\n\t\t\tif (errorMsg.includes(\"timeout\") || errorMsg.includes(\"timed out\")) {\n\t\t\t\tthrow new Error(\"OAuth flow timed out. Please try again.\");\n\t\t\t} else if (errorMsg.includes(\"403\") || errorMsg.includes(\"unauthorized\")) {\n\t\t\t\tthrow new Error(\"OAuth authorization failed. Please check your client credentials.\");\n\t\t\t} else if (errorMsg.includes(\"invalid_grant\")) {\n\t\t\t\tthrow new Error(\"OAuth authorization code is invalid or expired. Please try again.\");\n\t\t\t} else if (errorMsg.includes(\"ECONNREFUSED\") || errorMsg.includes(\"fetch failed\")) {\n\t\t\t\tthrow new Error(\"Could not connect to OAuth server. Please check the URLs and your network connection.\");\n\t\t\t} else {\n\t\t\t\tthrow new Error(`OAuth authentication failed: ${errorMsg}`);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.ctx.editor.onEscape = originalOnEscape;\n\t\t\texternalSignal?.removeEventListener(\"abort\", onExternalAbort);\n\t\t\tmanualInputClaim?.clear(\"Manual MCP OAuth input cleared\");\n\t\t\tflowClaim.release();\n\t\t}\n\t}\n\n\t/**\n\t * Fold a completed OAuth flow back into a server config. Owns the\n\t * persistence policy in one place: the auth block records the credential\n\t * pointer plus refresh material, the oauth block echoes the client id for\n\t * pre-auth reuse, and only a user-supplied client secret is ever written —","sourceCodeStart":1018,"sourceCodeEnd":1054,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/modes/controllers/mcp-command-controller.ts#L1018-L1054","documentation":"The MCP OAuth flow failed and the underlying error contained 'invalid_grant' — the standard OAuth2 token-endpoint error. The authorization code presented during the token exchange is invalid, already used, or expired, so the flow cannot obtain tokens.","triggerScenarios":"Replaying an authorization code that was already redeemed; the code expired because the token exchange happened too late; clock skew between client and server; the code was issued for a different redirect_uri or client_id than the exchange used.","commonSituations":"Retrying the flow and the callback server reusing a stale code; user pasting an old manual authorization code; provider with very short code lifetimes and a slow network.","solutions":["Restart the OAuth flow from scratch to get a fresh authorization code — codes are single-use","Do not reuse or re-run with a previously captured authorization code","Check client clock synchronization if the provider enforces strict expiry","Ensure redirect_uri and client_id in the token exchange exactly match the authorization request"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await runMcpOAuthFlow();\n} catch (err) {\n  if (err instanceof Error && err.message.includes('invalid or expired')) {\n    await runMcpOAuthFlow(); // fresh flow issues a fresh single-use code\n  }\n}","preventionTips":["Never replay authorization codes — each code is single-use","Start the token exchange immediately after receiving the code","Ensure redirect_uri and client_id match exactly between authorize and token requests","Keep client clocks synchronized (NTP)"],"tags":["oauth","mcp","invalid-grant","expired-code"],"backgroundTag":"oauth-invalid-grant","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}