{"record":{"id":"7c4161a81da66747","repo":"slopus/happy","slug":"token-exchange-failed","errorCode":null,"errorMessage":"Token exchange failed","messagePattern":"Token exchange failed","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"packages/happy-cli/src/commands/connect/authenticateClaude.ts","lineNumber":175,"sourceCode":"                    server.close();\n                    reject(new Error('No authorization code received'));\n                    return;\n                }\n\n                try {\n                    // Exchange code for tokens\n                    const tokens = await exchangeCodeForTokens(code, verifier, port, state);\n\n                    // Redirect to Anthropic's success page\n                    res.writeHead(302, {\n                        'Location': 'https://console.anthropic.com/oauth/code/success?app=claude-code'\n                    });\n                    res.end();\n\n                    server.close();\n                    resolve(tokens);\n                } catch (error) {\n                    res.writeHead(500);\n                    res.end('Token exchange failed');\n                    server.close();\n                    reject(error);\n                }\n            }\n        });\n\n        server.listen(port, '127.0.0.1', () => {\n            // console.log(`🔐 OAuth callback server listening on port ${port}`);\n        });\n\n        // Timeout after 5 minutes\n        setTimeout(() => {\n            server.close();\n            reject(new Error('Authentication timeout'));\n        }, 5 * 60 * 1000);\n    });\n}","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/slopus/happy/blob/b824cd0a4681d41af631a8e422a813873e4455b0/packages/happy-cli/src/commands/connect/authenticateClaude.ts#L157-L193","documentation":"After receiving the authorization code, the callback server exchanges it for tokens at the provider's token endpoint. If that HTTP exchange throws (network error, invalid grant, client authentication failure), the server responds 500 with 'Token exchange failed' and rejects the promise with the underlying error.","triggerScenarios":"The fetch/POST to the token endpoint fails or returns an error status: expired or already-used authorization code, wrong client_id/client_secret, redirect_uri mismatch with the token request, or network/connectivity failure.","commonSituations":"Authorization codes are single-use and short-lived — retries or duplicate callbacks cause invalid_grant; OAuth app credentials misconfigured; corporate proxy blocking the token endpoint; clock skew affecting token validation.","solutions":["Check the caught error (rejected promise/logs) for the provider's error body, e.g. invalid_grant or invalid_client","Restart the full connect flow to get a fresh authorization code — codes expire quickly and are single-use","Verify client credentials and that the redirect_uri in the token request matches the one used in the authorize request","Check network/proxy connectivity to the token endpoint"],"exampleFix":"// before\n} catch (error) {\n    res.writeHead(500);\n    res.end('Token exchange failed');\n// after\n} catch (error) {\n    res.writeHead(500);\n    res.end(`Token exchange failed: ${error instanceof Error ? error.message : error}`);\n    reject(error instanceof Error ? error : new Error(String(error)));","handlingStrategy":"try-catch","validationCode":"if (!process.env.ANTHROPIC_CLIENT_ID || !process.env.ANTHROPIC_CLIENT_SECRET) {\n  throw new Error('OAuth client credentials missing; token exchange would fail');\n}\nif (!navigator.onLine) throw new Error('Network offline; token exchange would fail');","typeGuard":null,"tryCatchPattern":"try {\n  const tokens = await authenticateClaude();\n} catch (e) {\n  if (String(e).includes('Token exchange failed')) {\n    console.error('Token endpoint rejected the exchange; get a fresh code (codes are single-use) and check credentials/network');\n  } else throw e;\n}","preventionTips":["Never reuse an authorization code — codes are single-use and expire in minutes","Verify client_id/secret and redirect_uri match between authorize and token requests","Check proxy/firewall access to the token endpoint before starting the flow","Retry by restarting the whole connect flow, not just the exchange"],"tags":["oauth","network","token-exchange","authentication"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"b824cd0a4681d41af631a8e422a813873e4455b0","analyzedAt":"2026-08-31T23:12:36.205Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}