mastra-ai/mastra · error
Failed to unlink repository (${res.status})
Error message
Failed to unlink repository (${res.status}) What it means
unlinkRepository sends DELETE to `/web/factory/projects/{id}/repositories/{repoId}` and throws this error for any non-ok status except 404, which is deliberately tolerated so unlinking stays idempotent. It means an existing repository link could not be removed.
Source
Thrown at mastracode/factory-ui/src/ui/domains/workspaces/services/github.ts:444
'Failed to link GitHub repository',
);
return toLinkedRepositoryPayload({ id: factoryProjectId, name: repo.fullName }, projectRepository);
}
/**
* Unlink a repository from its Factory project. Missing links are treated as
* already removed so unlink stays idempotent.
*/
export async function unlinkRepository(
baseUrl: string,
factoryProjectId: string,
projectRepositoryId: string,
): Promise<void> {
const res = await fetch(
`${baseUrl}/web/factory/projects/${encodeURIComponent(factoryProjectId)}/repositories/${encodeURIComponent(projectRepositoryId)}`,
{ method: 'DELETE', credentials: 'include', headers: { Accept: 'application/json' } },
);
if (!res.ok && res.status !== 404) throw new Error(`Failed to unlink repository (${res.status})`);
}
/**
* Delete a Factory project. The server cascades over its source-control
* connections (and their repository links). Missing projects are treated as
* already deleted so removal stays idempotent.
*/
export async function deleteFactoryProject(baseUrl: string, factoryProjectId: string): Promise<void> {
const res = await fetch(`${baseUrl}/web/factory/projects/${encodeURIComponent(factoryProjectId)}`, {
method: 'DELETE',
credentials: 'include',
headers: { Accept: 'application/json' },
});
if (!res.ok && res.status !== 404) throw new Error(`Failed to delete Factory (${res.status})`);
}
export interface CommitResult {
committed: boolean;View on GitHub (pinned to 75dd419e61)
Solutions
- Check the status in the message: 401/403 → re-authenticate or confirm project membership
- Ensure projectRepositoryId belongs to the given factoryProjectId and both ids are the server-side ids (not display names)
- Treat as best-effort: catch and refresh the project's repository list to see the actual state
- For 5xx, retry after a short delay; cascade cleanup may be retried safely
- Do not change code to also swallow 409/400 — those indicate a real mismatch that should surface
Example fix
// before
await unlinkRepository(baseUrl, projectId, repoId);
// after
try {
await unlinkRepository(baseUrl, projectId, repoId);
} catch (e) {
if (/\(40[13]\)/.test(e.message)) {
await reauth();
return unlinkRepository(baseUrl, projectId, repoId);
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
function canAttemptUnlink(ids: { factoryProjectId?: unknown; projectRepositoryId?: unknown }): boolean {
return typeof ids.factoryProjectId === 'string' && ids.factoryProjectId.length > 0 && typeof ids.projectRepositoryId === 'string' && ids.projectRepositoryId.length > 0;
} Type guard
const isBenignDeleteError = (e: unknown): boolean => e instanceof Error && /\(404\)/.test(e.message);
Try / catch
try {
await unlinkRepository(baseUrl, factoryProjectId, projectRepositoryId);
} catch (e) {
if (isBenignDeleteError(e)) {
// already unlinked: refresh and continue
} else if (/\((401|403)\)/.test(e.message)) {
promptReauth();
} else {
toast.error(e.message);
}
} finally {
queryClient.invalidateQueries(projectRepositoriesKey(factoryProjectId));
} Prevention
- Always invalidate the repository list after unlink, success or tolerated-404
- Match repo ids to the correct project before calling
- Check membership/permission on the project before showing the unlink action
- Keep the 404-tolerance contract: never surface 404 to users as an error
- Debounce unlink actions to prevent racing duplicate DELETEs
When it happens
Trigger: Non-ok, non-404 response: 401 unauthenticated session, 403 user lacks access to the Factory project, 400/422 malformed factoryProjectId or projectRepositoryId, 409 the link is referenced/locked, 5xx server failure during cascade cleanup.
Common situations: Unlinking while another user already deleted the project (404 — correctly swallowed); permissions changed so the current user is no longer a project member; expired session; passing a repo id from a different project.
Related errors
- Failed to delete Factory (${res.status})
- await extractError(res)
- ${body?.error} or Failed to save GitHub token (${res.status}
- Failed to remove GitHub token (${res.status})
- Failed to list repos (${res.status})
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/939a638bb254005d.
Report an issue: GitHub.