mastra-ai/mastra · error
Failed to remove GitHub token (${res.status})
Error message
Failed to remove GitHub token (${res.status}) What it means
deleteGithubPat sends DELETE to `${baseUrl}/web/github/pat?kind=...` and throws this error on any non-ok response. It means the server refused or failed to remove the stored GitHub PAT for that kind.
Source
Thrown at mastracode/factory-ui/src/ui/domains/workspaces/services/github.ts:183
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
credentials: 'include',
body: JSON.stringify({ token, kind }),
});
if (!res.ok) {
const body = (await res.json().catch(() => undefined)) as { error?: string } | undefined;
throw new Error(body?.error ?? `Failed to save GitHub token (${res.status})`);
}
}
/** Remove an org GitHub PAT. */
export async function deleteGithubPat(baseUrl: string, kind: GithubPatKind = 'default'): Promise<void> {
const res = await fetch(`${baseUrl}/web/github/pat?kind=${kind}`, {
method: 'DELETE',
headers: { Accept: 'application/json' },
credentials: 'include',
});
if (!res.ok) throw new Error(`Failed to remove GitHub token (${res.status})`);
}
/** List repos across the user's installations, optionally filtered by query. */
export async function listGithubRepos(baseUrl: string, query?: string): Promise<GithubRepo[]> {
const url = query ? `${baseUrl}/web/github/repos?q=${encodeURIComponent(query)}` : `${baseUrl}/web/github/repos`;
const res = await fetch(url, { headers: { Accept: 'application/json' }, credentials: 'include' });
if (!res.ok) throw new Error(`Failed to list repos (${res.status})`);
const body = (await res.json()) as { repos: GithubRepo[] };
return body.repos;
}
/** The GitHub source-control integration id registered on the server. */
const GITHUB_INTEGRATION_ID = 'github';
/** A Factory project row from `/web/factory/projects`. */
export interface FactoryProjectPayload {
id: string;
name: string;View on GitHub (pinned to 75dd419e61)
Solutions
- Check the status: 401/403 → re-authenticate or confirm the user owns the PAT; 404 → treat as already deleted and refresh local state
- Retry once after session refresh; transient 5xx on revocation is common
- Ensure the `kind` argument matches one registered on the server (default is 'default')
- Verify baseUrl/origin so the session cookie is included via credentials: 'include'
Example fix
// before
await deleteGithubPat(baseUrl); // assume 404 is fine
// after
try {
await deleteGithubPat(baseUrl, kind);
} catch (e) {
if (!/\(404\)/.test(e.message)) throw e; // tolerate already-removed
queryClient.invalidateQueries(githubPatKeys.all);
} Defensive patterns
Strategy: try-catch
Validate before calling
function canAttemptPatDelete(kind: unknown): boolean {
return typeof kind === 'string' && kind.length > 0;
} Type guard
const isAlreadyRemoved = (e: unknown): boolean => e instanceof Error && /\(404\)/.test(e.message);
Try / catch
try {
await deleteGithubPat(baseUrl, kind);
} catch (e) {
if (isAlreadyRemoved(e)) {
queryClient.invalidateQueries(githubPatKeys.all); // idempotent success
} else if (/\((401|403)\)/.test(e.message)) {
promptReauth();
} else {
throw e;
}
} Prevention
- Treat 404 as success for deletes to keep UI idempotent (mirrors unlinkRepository/deleteFactoryProject)
- Invalidate the PAT cache after delete instead of trusting the local flag
- Re-check session before destructive mutations
- Pass the exact `kind` used at save time; persist it with the token record
- Debounce the delete button to avoid duplicate concurrent DELETEs
When it happens
Trigger: Non-ok response from DELETE /web/github/pat: 401 unauthenticated session, 403 forbidden (PAT belongs to another user/org scope), 404 unknown kind or no stored PAT, 5xx server error during removal or GitHub revocation.
Common situations: Deleting a PAT after the session expired; calling delete twice and the second call hits 404 (no idempotent handling here, unlike unlinkRepository); wrong `kind` value passed (e.g. 'default' vs a custom kind the server doesn't recognize).
Related errors
- ${body?.error} or Failed to save GitHub token (${res.status}
- Failed to list repos (${res.status})
- GitHub OAuth token exchange failed: ${res.status}
- GitHub capabilities require a GitHub connection.
- Repository access did not include a bearer token for the Fac
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/1777a6464c66e823.
Report an issue: GitHub.