{"record":{"id":"9b3c292b8e0a6160","repo":"mastra-ai/mastra","slug":"failed-to-load-repository-settings-res-status","errorCode":null,"errorMessage":"Failed to load repository settings (${res.status})","messagePattern":"Failed to load repository settings \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory-ui/src/ui/domains/workspaces/services/github.ts","lineNumber":530,"sourceCode":"   * Shell command run inside every freshly created worktree before any agent\n   * execution (e.g. `pnpm i && pnpm build`). `null` when no setup step is\n   * configured.\n   */\n  setupCommand: string | null;\n  /** Best-effort shell command run before a session workspace is retired. */\n  teardownCommand: string | null;\n}\n\n/** Read a repository's worktree lifecycle settings. */\nexport async function fetchRepositorySettings(\n  baseUrl: string,\n  projectRepositoryId: string,\n): Promise<RepositorySettings> {\n  const res = await fetch(`${baseUrl}/web/github/projects/${encodeURIComponent(projectRepositoryId)}/settings`, {\n    headers: { Accept: 'application/json' },\n    credentials: 'include',\n  });\n  if (!res.ok) throw new Error(`Failed to load repository settings (${res.status})`);\n  return (await res.json()) as RepositorySettings;\n}\n\n/** Persist a repository's lifecycle commands. Pass `null` (or blank) to clear one. */\nexport async function saveRepositorySettings(\n  baseUrl: string,\n  projectRepositoryId: string,\n  settings: RepositorySettings,\n): Promise<RepositorySettings> {\n  return postRepositoryGitOp<RepositorySettings>(baseUrl, projectRepositoryId, 'settings', settings);\n}\n","sourceCodeStart":512,"sourceCodeEnd":542,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory-ui/src/ui/domains/workspaces/services/github.ts#L512-L542","documentation":"fetchRepositorySettings in mastracode/factory-ui/src/ui/domains/workspaces/services/github.ts throws this when the GET to `${baseUrl}/web/github/projects/${projectRepositoryId}/settings` returns a non-OK HTTP status. The status code is embedded in the message so developers can distinguish 404 (unknown repository id) from 401/403 (auth) or 500 (server fault). The raw fetch response body is discarded, so server-side error details are not surfaced.","triggerScenarios":"Any response with res.ok === false from the settings endpoint: nonexistent or stale projectRepositoryId (404), expired/missing session cookie (401), insufficient permissions on the GitHub-backed project (403), or backend failure (500). It fires for every non-2xx; 404 is NOT tolerated here unlike deleteUserSession.","commonSituations":"React Query's useRepositorySettingsQuery renders a repository settings panel for a repository that was deleted or whose id changed after a re-sync; the user's session cookie expired mid-tab; a proxy/ingress returns 502; the workspace backend restarted with a data migration that invalidated old project repository ids.","solutions":["Log the status from the message and call the same URL manually (with credentials: 'include') to inspect the response body for the real server error.","Verify projectRepositoryId is current — re-fetch the repository list and confirm the id still exists (404 usually means stale id).","If 401/403, re-authenticate / refresh the session cookie and confirm the user has access to the project.","Retry on transient statuses (502/503/504) — React Query's retry may already handle this; check retry config in useRepositorySettingsQuery."],"exampleFix":"// before: server error body is lost\nif (!res.ok) throw new Error(`Failed to load repository settings (${res.status})`);\n// after: include server-provided detail\ntype SettingsError = { error?: string };\nconst errBody: SettingsError = res.ok ? {} : await res.clone().json().catch(() => ({}));\nif (!res.ok) throw new Error(errBody.error ?? `Failed to load repository settings (${res.status})`);","handlingStrategy":"try-catch","validationCode":"// no client-side pre-check can guarantee the HTTP result, but validate inputs and auth up front\nif (!projectRepositoryId) throw new Error('projectRepositoryId is required');\nconst authed = document.cookie.includes('session='); // heuristic: ensure session cookie present\nif (!authed) await refreshSession();","typeGuard":"function isRepositorySettings(v: unknown): v is RepositorySettings {\n  return typeof v === 'object' && v !== null && 'id' in v;\n}","tryCatchPattern":"try {\n  const settings = await fetchRepositorySettings(baseUrl, id);\n} catch (err) {\n  const msg = err instanceof Error ? err.message : String(err);\n  const status = Number(msg.match(/\\((\\d{3})\\)/)?.[1] ?? 0);\n  if (status === 404) showEmptySettings();\n  else if (status === 401 || status === 403) redirectToLogin();\n  else showToast('Could not load settings; retrying...');\n}","preventionTips":["Refresh the repository list before deep-linking into a settings panel so ids are current.","Configure React Query retry to only retry 5xx/network errors, not 4xx.","Re-authenticate proactively when the session cookie is near expiry."],"tags":["http","fetch","react-query","network"],"backgroundTag":"http-request-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}