BloopAI/vibe-kanban · error · Error
Failed to fetch identity (${res.status})
Error message
Failed to fetch identity (${res.status}) What it means
getIdentity fetches GET {API_BASE}/v1/identity via authenticatedFetch to retrieve the current user's id/username/email. Non-ok responses after the built-in single 401-refresh retry throw this Error. It is commonly surfaced through TanStack-style queries (identityQuery), where it appears as the query's error.
Source
Thrown at packages/remote-web/src/shared/lib/api.ts:207
method: "POST",
});
} finally {
await clearTokens();
}
}
export async function listOrganizations(): Promise<ListOrganizationsResponse> {
const res = await authenticatedFetch(`${API_BASE}/v1/organizations`);
if (!res.ok) {
throw new Error(`Failed to list organizations (${res.status})`);
}
return res.json();
}
export async function getIdentity(): Promise<IdentityResponse> {
const res = await authenticatedFetch(`${API_BASE}/v1/identity`);
if (!res.ok) {
throw new Error(`Failed to fetch identity (${res.status})`);
}
return res.json();
}
export async function listOrganizationProjects(
organizationId: string,
): Promise<Project[]> {
const params = new URLSearchParams({
organization_id: organizationId,
});
const res = await authenticatedFetch(`${API_BASE}/v1/projects?${params}`);
if (!res.ok) {
throw new Error(`Failed to list projects (${res.status})`);
}
const body = (await res.json()) as { projects: Project[] };
return body.projects;View on GitHub (pinned to 4deb7eca8f)
Solutions
- Redirect the user to login: clear stored tokens and re-authenticate.
- Check status: 401 after retry = tokens unusable (re-login); 403 = account access issue; 5xx = backend problem, check server logs.
- Verify VITE_API_BASE_URL points at the correct remote API.
- In the consuming query, handle the error state gracefully instead of crashing the identity screen.
Example fix
// before
if (!res.ok) {
throw new Error(`Failed to fetch identity (${res.status})`);
}
// after
if (!res.ok) {
const err = new Error(`Failed to fetch identity (${res.status})`);
(err as Error & { status: number }).status = res.status;
if (res.status === 401) await clearTokens();
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
const accessToken = await getToken();
if (!accessToken) {
redirectToLogin();
} Type guard
function isIdentityResponse(v: unknown): v is IdentityResponse {
const r = v as IdentityResponse;
return !!r && typeof r.user_id === 'string' && typeof r.email === 'string';
} Try / catch
const identityQuery = useQuery({
queryKey: ['identity'],
queryFn: getIdentity,
retry: (count, err) => {
const status = Number(/\((\d{3})\)$/.exec((err as Error).message)?.[1]);
return status >= 500 && count < 2; // never retry auth failures
},
});
if (identityQuery.error) {
const msg = (identityQuery.error as Error).message;
if (msg.includes('(401)')) redirectToLogin();
} Prevention
- Configure the identity query to not retry on 4xx and to redirect to login on 401.
- Clear stale tokens on app boot when identity fails with 401.
- Show a 'session expired' notice rather than a blank/broken page.
- Verify VITE_API_BASE_URL after each backend redeploy.
When it happens
Trigger: GET /v1/identity returns 401 after the automatic refresh also failed (refresh token expired/revoked), 403 (account disabled), or 5xx from the remote server. Also when the API base URL is wrong and the endpoint doesn't exist.
Common situations: App restored with stale tokens after server-side token revocation or a server database reset; backend redeployed/invalidating sessions; user account removed while a tab kept old tokens.
Related errors
- Failed to accept invitation (${res.status})
- Failed to list organizations (${res.status})
- Invitation not found (${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/cf02df140681a2f4.
Report an issue: GitHub.