Significant-Gravitas/AutoGPT · error · NotFoundError

Invitation {invitation_id} not found

Error message

Invitation {invitation_id} not found

What it means

Raised by DELETE revoke-invitation when the OrgInvitation record with the given invitation_id either does not exist or exists but its orgId does not match the org_id in the path. This prevents an admin of org A from revoking (or even probing) invitations of org B. It is a NotFoundError (mapped to HTTP 404).

Source

Thrown at autogpt_platform/backend/backend/api/features/orgs/invitation_routes.py:128

@org_router.delete(
    "/{invitation_id}",
    summary="Revoke invitation",
    tags=["orgs", "invitations"],
    status_code=204,
)
async def revoke_invitation(
    org_id: str,
    invitation_id: str,
    ctx: Annotated[
        RequestContext,
        Security(requires_org_permission(OrgAction.MANAGE_MEMBERS)),
    ],
) -> None:
    _verify_org_path(ctx, org_id)
    invitation = await prisma.orginvitation.find_unique(where={"id": invitation_id})
    if invitation is None or invitation.orgId != org_id:
        raise NotFoundError(f"Invitation {invitation_id} not found")

    await prisma.orginvitation.update(
        where={"id": invitation_id},
        data={"revokedAt": datetime.now(timezone.utc)},
    )


# --- Token-based endpoints (under /api/invitations) ---


@router.post(
    "/{token}/accept",
    summary="Accept invitation",
    tags=["invitations"],
    dependencies=[Security(requires_user)],
)
async def accept_invitation(
    token: str,

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Confirm invitation_id comes from the pending-invitations list of the same org_id in the URL.
  2. If the 404 is unexpected, query prisma.orginvitation.find_unique for the id and inspect its orgId.
  3. Refresh the invitations table after the error and treat a 404 as 'already gone' — remove the row from the UI.
  4. Check for trailing whitespace or URL-encoding issues in the id parameter.

Example fix

# before
invitation = await prisma.orginvitation.find_unique(where={'id': invitation_id})
# after — verify org ownership before acting
invitation = await prisma.orginvitation.find_unique(where={'id': invitation_id})
if invitation is None or invitation.orgId != org_id:
    return None  # treat as already revoked/removed in the UI
Defensive patterns

Strategy: try-catch

Validate before calling

const pending = await api.get(`/api/orgs/${orgId}/invitations/pending`).then(r => r.data);
const exists = pending.some(i => i.id === invitationId);

Try / catch

try {
  await api.delete(`/api/orgs/${orgId}/invitations/${invitationId}/revoke`);
} catch (e) {
  if (e.status === 404) { removeInvitationFromUI(invitationId); return; }
  throw e;
}

Prevention

When it happens

Trigger: POST/DELETE to /api/orgs/{org_id}/invitations/{invitation_id}/revoke with an invitation id from another org, a deleted invitation, or a malformed/typo'd id. Also when the invitation list in the UI is stale and the row was already revoked/removed.

Common situations: Admin has multiple orgs open and copies an invitation id across contexts; concurrent admin already revoked and cleanup removed the record; frontend keeps a cached list of invitations after org switch.

Related errors


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