mastra-ai/mastra · error

Failed to list repos (${res.status})

Error message

Failed to list repos (${res.status})

What it means

listGithubRepos GETs `${baseUrl}/web/github/repos` (optionally with `?q=`) and throws this error when the response is not ok, before attempting to parse `{ repos: GithubRepo[] }`. It signals the repo listing could not be retrieved for the user's GitHub App installations.

Source

Thrown at mastracode/factory-ui/src/ui/domains/workspaces/services/github.ts:190

    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;
  /** Org-wide default model for factory runs; null when unset. */
  defaultModelId?: string | null;
  /** Whether new Slack sessions create Work-board items for this Factory. */
  slackWorkItemsEnabled?: boolean;
  /** Whether Factory rules may start agent runs without someone asking for them. */
  autoRunEnabled?: boolean;
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check the status: 401/403 → reinstall/re-authorize the GitHub App or re-login; 429 → back off and retry after the rate-limit window
  2. Handle the throw in the query hook (React Query will retry automatically) and show an empty/error state instead of crashing
  3. Verify the installation is still active for the target org on GitHub → Settings → Applications
  4. Confirm server egress to api.github.com is allowed in self-hosted deployments
  5. Retry with a narrower `q` if a broad query correlates with rate-limit hits

Example fix

// before
const repos = await listGithubRepos(baseUrl, query);
// after
const repos = await listGithubRepos(baseUrl, query).catch((e) => {
  if (/\(429\)/.test(e.message)) return []; // rate-limited: show empty state
  throw e;
});
Defensive patterns

Strategy: retry

Validate before calling

function canListRepos(): boolean {
  return typeof baseUrl === 'string' && baseUrl.length > 0; // listing needs no client-side input; ensure a query hook is mounted with an authenticated session
}

Type guard

function isGithubRepoList(b: unknown): b is { repos: GithubRepo[] } {
  return typeof b === 'object' && b !== null && Array.isArray((b as { repos?: unknown }).repos);
}

Try / catch

useQuery({
  queryKey: ['github','repos', query],
  queryFn: () => listGithubRepos(baseUrl, query),
  retry: (count, err) => /\((429|5\d\d)\)/.test(err.message) && count < 3,
  staleTime: 60_000,
});

Prevention

When it happens

Trigger: Non-ok response from GET /web/github/repos: 401 when no GitHub App installation is linked or the session is unauthenticated, 403 insufficient permissions/installation revoked, 429 GitHub rate limit proxied by the server, 502/504 when the server's call to the GitHub API fails or times out.

Common situations: GitHub App installation uninstalled or suspended; token expired server-side; searching repos while GitHub API rate limit is exhausted; server cannot reach GitHub (network egress blocked in self-hosted environments).

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/fc33fdfe5310bc70. Report an issue: GitHub.