Significant-Gravitas/AutoGPT · warning · Error
PKCE verifier not found in session
Error message
PKCE verifier not found in session
What it means
Raised by approve_transfer when the caller's active org is the source org and sourceApprovedByUserId is already set. Each side of a transfer may approve exactly once; a second approval attempt from the source side is rejected. Guards against double-approval by different users of the same org.
Source
Thrown at autogpt_platform/backend/backend/cli/oauth_tool.py:683
providers: providersBase64,
redirect_uri: config.redirectUri,
state: currentState
}});
const wizardUrl = `${{config.platformUrl}}/auth/integrations/setup-wizard?${{params}}`;
log(`Redirecting to: ${{wizardUrl}}`);
sessionStorage.setItem('wizard_state', currentState);
window.location.href = wizardUrl;
}}
async function exchangeCodeForTokens(code) {{
log('Exchanging authorization code for tokens...');
const verifier = sessionStorage.getItem('oauth_pkce_verifier');
if (!verifier) {{
throw new Error('PKCE verifier not found in session');
}}
// 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) {{View on GitHub (pinned to 9c8bb5550f)
Solutions
- Check the transfer's sourceApprovedByUserId / targetApprovedByUserId fields in the UI and hide the approve action for a side that has already approved.
- Catch this ValueError in the client and treat it as success-equivalent (the org's approval is recorded) after re-fetching the transfer.
- Add idempotency: if sourceApprovedByUserId == user_id, return the current row instead of raising.
Example fix
# before
await approve_transfer(tid, user_id, org_id)
# after
tr = await get_transfer(tid)
if tr.source_approved_by_user_id is None or tr.target_approved_by_user_id is None:
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.source_org_id and tr.source_approved_by_user_id is not None:
return # source already approved; nothing to do Type guard
def source_already_approved(tr: TransferResponse, org_id: str) -> bool:
return org_id == tr.source_org_id and tr.source_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 # idempotent: approval recorded
else:
raise Prevention
- Hide the approve control for a side whose *ApprovedByUserId is set
- Make approve idempotent client-side by checking the approval fields first
- Coordinate among org admins to avoid duplicate approvals
When it happens
Trigger: User A in the source org approves (sets sourceApprovedByUserId), then User B (or User A again) in the same org calls approve on the same transfer. Any POST approve from the source org after sourceApprovedByUserId is non-null.
Common situations: Two admins in the same org both clicking approve; a retry of a timed-out approve request that actually succeeded; frontend not reflecting that the current org already approved.
Related errors
- Token exchange failed
- Failed to reset usage
- Failed to update tier
- Failed to start OAuth flow
- Login failed
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/d1bf52a06e1660ef.
Report an issue: GitHub.