{"record":{"id":"db541399a9a72f60","repo":"Significant-Gravitas/AutoGPT","slug":"token-exchange-failed","errorCode":null,"errorMessage":"Token exchange failed","messagePattern":"Token exchange failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"autogpt_platform/backend/backend/cli/oauth_tool.py","lineNumber":703,"sourceCode":"\n            // Use local proxy to avoid CORS issues\n            // The proxy forwards the request to the backend\n            const response = await fetch('/proxy/token', {{\n                method: 'POST',\n                headers: {{ 'Content-Type': 'application/json' }},\n                body: JSON.stringify({{\n                    grant_type: 'authorization_code',\n                    code: code,\n                    redirect_uri: config.redirectUri,\n                    client_id: config.clientId,\n                    client_secret: config.clientSecret,\n                    code_verifier: verifier\n                }})\n            }});\n\n            if (!response.ok) {{\n                const error = await response.json();\n                throw new Error(error.detail || 'Token exchange failed');\n            }}\n\n            return response.json();\n        }}\n\n        // Handle callback on page load\n        window.addEventListener('load', async () => {{\n            const params = new URLSearchParams(window.location.search);\n\n            // Check for OAuth callback\n            if (params.has('code')) {{\n                const code = params.get('code');\n                const state = params.get('state');\n                const savedState = sessionStorage.getItem('oauth_state');\n\n                log(`Received authorization code: ${{code.substring(0, 20)}}...`);\n\n                if (state !== savedState) {{","sourceCodeStart":685,"sourceCodeEnd":721,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/backend/backend/cli/oauth_tool.py#L685-L721","documentation":"Mirror of the source-side guard: raised by approve_transfer when the caller's active org is the target org and targetApprovedByUserId is already set. The target side may approve only once per transfer.","triggerScenarios":"Any POST approve from a user whose active org equals tr.targetOrganizationId after targetApprovedByUserId was set — e.g. a second target-org admin approving, or a retried request.","commonSituations":"Multiple target-org admins acting on the same transfer; retry of an approve that already committed; UI showing an approve button for a side that already approved.","solutions":["Drive the approve button visibility off targetApprovedByUserId (and sourceApprovedByUserId) per side.","Catch the ValueError and re-fetch to confirm the target approval is recorded, then continue the flow.","Return the existing row (idempotent approve) when the same org/user approves twice."],"exampleFix":"# before\nawait approve_transfer(tid, user_id, org_id)\n\n# after\ntr = await get_transfer(tid)\nalready = (org_id == tr.target_org_id and tr.target_approved_by_user_id) or \\\n         (org_id == tr.source_org_id and tr.source_approved_by_user_id)\nif not already:\n    await approve_transfer(tid, user_id, org_id)","handlingStrategy":"validation","validationCode":"tr = await get_transfer(transfer_id)\nif org_id == tr.target_org_id and tr.target_approved_by_user_id is not None:\n    return  # target already approved","typeGuard":"def target_already_approved(tr: TransferResponse, org_id: str) -> bool:\n    return org_id == tr.target_org_id and tr.target_approved_by_user_id is not None","tryCatchPattern":"try:\n    await approve_transfer(tid, user_id, org_id)\nexcept ValueError as e:\n    if \"already approved\" in str(e):\n        pass\n    else:\n        raise","preventionTips":["Reflect both approval fields in the UI per side","Do not retry approve without re-fetching the transfer","Watch the status field: single-sided approvals move it to *_APPROVED"],"tags":["transfers","idempotency","approval"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}