{"record":{"id":"20b62d9e01bc821d","repo":"can1357/oh-my-pi","slug":"oauth-authentication-failed-errormsg","errorCode":null,"errorMessage":"OAuth authentication failed: ${errorMsg}","messagePattern":"OAuth authentication failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/modes/controllers/mcp-command-controller.ts","lineNumber":1040,"sourceCode":"\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 —\n\t * DCR-issued secrets stay embedded in the stored credential so they cannot\n\t * leak into (possibly shared/committed) config files.\n\t */\n\t#persistOAuthResult(","sourceCodeStart":1022,"sourceCodeEnd":1058,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/modes/controllers/mcp-command-controller.ts#L1022-L1058","documentation":"This is the catch-all branch of the MCP OAuth login flow in MCPCommandController. When the underlying MCPOAuthFlow (dynamic client registration, authorization-code exchange, or token fetch) fails with an error that does not match the known timeout/403/invalid_grant/network patterns, the controller rethrows it wrapped as \"OAuth authentication failed: <original message>\" so the user still sees the root cause. It signals that the OAuth handshake failed for a reason the controller does not specifically classify.","triggerScenarios":"Running /mcp auth (or a reauth) against an MCP server where the OAuth flow throws an unclassified error: the provider rejects the client_id or redirect_uri, DCR registration fails, the token endpoint returns an unexpected status/body, the callback server port is taken, or the server returns a non-standard error code not containing 'timeout', '403', 'unauthorized', 'invalid_grant', 'ECONNREFUSED', or 'fetch failed'.","commonSituations":"Misconfigured OAuth client credentials in the MCP server config; the authorization server returning 400 invalid_client or invalid_scope; an IdP that does not support RFC 8414 metadata discovery; a corporate proxy returning a non-standard error page; a server whose token endpoint replies with a 500 that the flow surfaces verbatim.","solutions":["Read the embedded original message after the colon — it names the actual OAuth failure (e.g. invalid_client, invalid_scope) and fix the client credentials/scopes in the server config accordingly.","Verify the server's OAuth discovery metadata is reachable: curl <server-url>/.well-known/oauth-authorization-server and .well-known/oauth-protected-resource.","Re-run the auth flow — transient token-endpoint errors (5xx) resolve on retry.","If the provider requires a pre-registered client, add the correct clientId/clientSecret to the MCP server's auth block instead of relying on dynamic client registration."],"exampleFix":"// before: relying on DCR against a provider that rejects it\n{ \"type\": \"http\", \"url\": \"https://mcp.example.com/mcp\" }\n// after: supply pre-registered OAuth client credentials\n{\n  \"type\": \"http\",\n  \"url\": \"https://mcp.example.com/mcp\",\n  \"oauth\": { \"clientId\": \"my-registered-client\", \"clientSecret\": \"...\" }\n}","handlingStrategy":"try-catch","validationCode":"const meta = await fetch(`${serverUrl.replace(/\\/$/, '')}/.well-known/oauth-authorization-server`);\nif (!meta.ok) throw new Error(`No OAuth metadata at ${serverUrl} (HTTP ${meta.status})`);","typeGuard":"function isOAuthError(err: unknown): err is Error & { oauthFailure: true } {\n  return err instanceof Error && err.message.startsWith(\"OAuth authentication failed:\");\n}","tryCatchPattern":"try {\n  await runMcpOAuthLogin(serverName);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"OAuth authentication failed:\")) {\n    const rootCause = err.message.slice(\"OAuth authentication failed: \".length);\n    logger.warn(\"MCP OAuth failed\", { serverName, rootCause }); // inspect rootCause for invalid_client/scope\n  } else throw err;\n}","preventionTips":["Pre-register an OAuth client (clientId/clientSecret in the server's oauth config block) with providers that reject dynamic client registration.","Curl the server's .well-known/oauth-authorization-server endpoint before wiring the server into config.","Match requested scopes to what the provider actually grants — invalid_scope surfaces here.","Retry transient 5xx failures before assuming a config problem."],"tags":["oauth","mcp","authentication"],"backgroundTag":"oauth-flow-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}