BloopAI/vibe-kanban · error · Error
Failed to accept invitation (${res.status})
Error message
Failed to accept invitation (${res.status}) What it means
acceptInvitation POSTs to {API_BASE}/v1/invitations/{token}/accept with a Bearer access token to join the invited organization. Any non-ok response triggers this generic Error containing only the status code. Unlike refreshTokens, it does not attach the status as a property, so callers can only parse the message to distinguish causes.
Source
Thrown at packages/remote-web/src/shared/lib/api.ts:137
if (!res.ok) {
throw new Error(`Invitation not found (${res.status})`);
}
return res.json();
}
export async function acceptInvitation(
token: string,
accessToken: string,
): Promise<AcceptInvitationResponse> {
const res = await fetch(`${API_BASE}/v1/invitations/${token}/accept`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
});
if (!res.ok) {
throw new Error(`Failed to accept invitation (${res.status})`);
}
return res.json();
}
export async function refreshTokens(
refreshToken: string,
): Promise<{ access_token: string; refresh_token: string }> {
const res = await fetch(`${API_BASE}/v1/tokens/refresh`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ refresh_token: refreshToken }),
});
if (!res.ok) {
const err = new Error(`Token refresh failed (${res.status})`);
(err as Error & { status: number }).status = res.status;
throw err;
}
return res.json();View on GitHub (pinned to 4deb7eca8f)
Solutions
- Ensure the user is logged in as the invited account and pass a fresh access token; call refreshTokens if it may be stale.
- If status is 401/403, re-authenticate (the token is expired or for the wrong user).
- If status is 404/410, request a new invitation from the admin.
- Check the server response body (e.g. via devtools) for the specific rejection reason and surface it to the user.
Example fix
// before
if (!res.ok) {
throw new Error(`Failed to accept invitation (${res.status})`);
}
// after
if (!res.ok) {
const err = new Error(`Failed to accept invitation (${res.status})`);
(err as Error & { status: number }).status = res.status;
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
const accessToken = await getToken();
if (!accessToken) {
// force login before attempting acceptance
redirectToLogin();
} Type guard
function isAcceptInvitationResponse(v: unknown): v is AcceptInvitationResponse {
const r = v as AcceptInvitationResponse;
return !!r && typeof r.organization_id === 'string' && typeof r.role === 'string';
} Try / catch
try {
const result = await acceptInvitation(token, accessToken);
navigate(`/org/${result.organization_slug}`);
} catch (e) {
const status = Number(/\((\d{3})\)$/.exec((e as Error).message)?.[1]);
if (status === 401 || status === 403) {
await triggerRefresh().catch(() => redirectToLogin());
} else {
show('Unable to accept this invitation — it may be expired or already used.');
}
} Prevention
- Always send a freshly obtained access token; refresh proactively if it may be near expiry.
- Confirm the logged-in user matches the invited email before showing the accept button.
- Handle single-use invitations: disable the accept button after success.
- Parse the status code out of the message or patch the throw site to attach status as a property.
When it happens
Trigger: POST /v1/invitations/{token}/accept returns 401/403 (access token expired, invalid, or belonging to a different user than the invitee), 404 (token unknown/already accepted), 410 (expired invitation), or 409/422 (user already a member, role conflict).
Common situations: User's session token expired between login and accepting; the access token passed in is from a different account than the invited email; invitation link reused after acceptance; invite expired while the user sat on the acceptance page.
Related errors
- Invitation not found (${res.status})
- Failed to list organizations (${res.status})
- Failed to fetch identity (${res.status})
- Failed to list projects (${res.status})
- Logout failed with status ${response.status}
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/52d90c377bfee2b2.
Report an issue: GitHub.