Significant-Gravitas/AutoGPT · warning · Error

Token exchange failed

Error message

Token exchange failed

What it means

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.

Solutions

  1. Drive the approve button visibility off targetApprovedByUserId (and sourceApprovedByUserId) per side.
  2. Catch the ValueError and re-fetch to confirm the target approval is recorded, then continue the flow.
  3. Return the existing row (idempotent approve) when the same org/user approves twice.

Example fix

# before
await approve_transfer(tid, user_id, org_id)

# after
tr = await get_transfer(tid)
already = (org_id == tr.target_org_id and tr.target_approved_by_user_id) or \
         (org_id == tr.source_org_id and tr.source_approved_by_user_id)
if not already:
    await approve_transfer(tid, user_id, org_id)
Defensive patterns

Strategy: validation

Validate before calling

tr = await get_transfer(transfer_id)
if org_id == tr.target_org_id and tr.target_approved_by_user_id is not None:
    return  # target already approved

Type guard

def target_already_approved(tr: TransferResponse, org_id: str) -> bool:
    return org_id == tr.target_org_id and tr.target_approved_by_user_id is not None

Try / catch

try:
    await approve_transfer(tid, user_id, org_id)
except ValueError as e:
    if "already approved" in str(e):
        pass
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14). Data as JSON: /api/errors/db541399a9a72f60. Report an issue: GitHub.

Appendix: source

Thrown at autogpt_platform/backend/backend/cli/oauth_tool.py:703

            // Use local proxy to avoid CORS issues
            // The proxy forwards the request to the backend
            const response = await fetch('/proxy/token', {{
                method: 'POST',
                headers: {{ 'Content-Type': 'application/json' }},
                body: JSON.stringify({{
                    grant_type: 'authorization_code',
                    code: code,
                    redirect_uri: config.redirectUri,
                    client_id: config.clientId,
                    client_secret: config.clientSecret,
                    code_verifier: verifier
                }})
            }});

            if (!response.ok) {{
                const error = await response.json();
                throw new Error(error.detail || 'Token exchange failed');
            }}

            return response.json();
        }}

        // Handle callback on page load
        window.addEventListener('load', async () => {{
            const params = new URLSearchParams(window.location.search);

            // Check for OAuth callback
            if (params.has('code')) {{
                const code = params.get('code');
                const state = params.get('state');
                const savedState = sessionStorage.getItem('oauth_state');

                log(`Received authorization code: ${{code.substring(0, 20)}}...`);

                if (state !== savedState) {{

View on GitHub (pinned to 9c8bb5550f)