Significant-Gravitas/AutoGPT · warning · HTTPException
Invitation has expired
Error message
Invitation has expired
What it means
Raised by POST /api/invitations/{token}/accept when the current UTC time is past the invitation's expiresAt (created as now + INVITATION_TTL_DAYS at create time). The token is time-limited by design. HTTP 400.
Source
Thrown at autogpt_platform/backend/backend/api/features/orgs/invitation_routes.py:157
@router.post(
"/{token}/accept",
summary="Accept invitation",
tags=["invitations"],
dependencies=[Security(requires_user)],
)
async def accept_invitation(
token: str,
user_id: Annotated[str, Security(get_user_id)],
) -> dict:
invitation = await prisma.orginvitation.find_unique(where={"token": token})
if invitation is None:
raise NotFoundError("Invitation not found")
if invitation.acceptedAt is not None:
raise HTTPException(400, detail="Invitation already accepted")
if invitation.revokedAt is not None:
raise HTTPException(400, detail="Invitation has been revoked")
if invitation.expiresAt < datetime.now(timezone.utc):
raise HTTPException(400, detail="Invitation has expired")
# Verify the accepting user's email matches the invitation
accepting_user = await prisma.user.find_unique(where={"id": user_id})
if accepting_user is None:
raise HTTPException(401, detail="User not found")
if accepting_user.email.lower() != invitation.email.lower():
raise HTTPException(
403,
detail="This invitation was sent to a different email address",
)
# Add user to org (idempotent — handles race condition from concurrent accepts)
try:
await org_db.add_org_member(
org_id=invitation.orgId,
user_id=user_id,
is_admin=invitation.isAdmin,
is_billing_manager=invitation.isBillingManager,View on GitHub (pinned to 9c8bb5550f)
Solutions
- Ask the admin to send a fresh invitation — expired tokens cannot be extended.
- If you administer the backend and truly need a longer window, adjust INVITATION_TTL_DAYS and regenerate; otherwise leave the default.
- Client: compare the expiry shown in the invitation payload (GET pending) with current time before offering the Accept button.
- Check server clock synchronization (NTP) if you believe the invitation should still be valid.
Defensive patterns
Strategy: validation
Validate before calling
const inv = await api.get('/api/invitations/pending').then(r => r.data.find(i => i.token === token));
if (inv && new Date(inv.expiresAt) < new Date()) {
show('This invitation has expired. Ask for a new one.');
} Try / catch
try {
await api.post(`/api/invitations/${token}/accept`);
} catch (e) {
if (e.status === 400 && e.detail === 'Invitation has expired') { show('Invitation expired'); return; }
throw e;
} Prevention
- Check expiresAt client-side before offering the accept action
- Remind users invitation links have a TTL
- Keep server clocks NTP-synced
When it happens
Trigger: User clicks an invitation link older than the TTL (INVITATION_TTL_DAYS), or a system clock skew makes now() appear past expiry; accepting a link days after the email arrived.
Common situations: User leaves invitation emails unread in the inbox; onboarding emails queued in spam for days; long-lived bookmarked links; server clock drift.
Related errors
- Teams not found in this organization: {invalid}
- Invitation already accepted
- Invitation has been revoked
- Invitation already revoked
- Invalid or expired state token
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/d88085587638d8e6.
Report an issue: GitHub.