{"record":{"id":"54c9af52b8b45ff0","repo":"mastra-ai/mastra","slug":"request-failed-res-status-server-provided-m-54c9af","errorCode":null,"errorMessage":"Request failed (${res.status}) / server-provided message","messagePattern":"Request failed \\((.+?)\\) / server-provided message","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory-ui/src/ui/domains/factory/services/intake.ts","lineNumber":58,"sourceCode":"  return selection.enabled ? selection : { ...selection, enabled: true };\n}\n\nasync function requestIntakeConfig(baseUrl: string, init?: RequestInit): Promise<IntakeConfig> {\n  const res = await fetch(`${baseUrl}/web/intake/config`, {\n    headers: { Accept: 'application/json', ...(init?.body ? { 'content-type': 'application/json' } : {}) },\n    credentials: 'include',\n    ...init,\n  });\n  if (!res.ok) {\n    let message = `Request failed (${res.status})`;\n    try {\n      const body = (await res.json()) as { error?: string; message?: string };\n      if (body.message) message = body.message;\n      else if (body.error) message = body.error;\n    } catch {\n      /* ignore non-JSON */\n    }\n    throw new Error(message);\n  }\n  const { config } = (await res.json()) as { config?: Partial<Record<string, IntakeSelection>> };\n  return normalizeIntakeConfig(config);\n}\n\n/** Read the caller's intake config (server falls back to the defaults). */\nexport async function fetchIntakeConfig(baseUrl: string): Promise<IntakeConfig> {\n  return requestIntakeConfig(baseUrl);\n}\n\n/** Save the caller's intake config; resolves to the persisted config. */\nexport async function saveIntakeConfig(baseUrl: string, config: IntakeConfig): Promise<IntakeConfig> {\n  return requestIntakeConfig(baseUrl, { method: 'PUT', body: JSON.stringify(config) });\n}\n\n/** Routing of one intake source to the Factory project its items land in. */\nexport interface IntakeSourceBinding {\n  integrationId: string;","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory-ui/src/ui/domains/factory/services/intake.ts#L40-L76","documentation":"requestIntakeConfig is the shared fetch helper for the intake config API, used by fetchIntakeConfig and saveIntakeConfig. On a non-OK response it throws an Error preferring the server body's message then error field, falling back to 'Request failed (<status>)'. On success it normalizes the returned config into IntakeSelection records.","triggerScenarios":"Any non-OK res.status from GET (fetchIntakeConfig) or save (saveIntakeConfig) of the intake config: 401 unauthenticated, 403 forbidden for the target user/scope, 400 when saved selections fail server validation, or 5xx backend errors.","commonSituations":"Session cookie expired before saving intake config, submitting intake selections containing keys/values the server rejects after a schema change, another user's config requested without permission, or the intake service returning 502 during deploy.","solutions":["Read error.message for the server-provided cause; otherwise use the status code","Re-authenticate if the status is 401/403","For saves, validate intake selection keys/values against the current IntakeSelection schema before calling saveIntakeConfig","If 5xx, retry after the backend is healthy"],"exampleFix":"// before\nawait saveIntakeConfig(baseUrl, { legacyField: { id: 'x' } } as Record<string, IntakeSelection>);\n// after\nconst cfg = normalizeIntakeConfig({ area: { id: 'x' } });\nawait saveIntakeConfig(baseUrl, cfg);","handlingStrategy":"validation","validationCode":"function isValidIntakeConfig(cfg: unknown): cfg is Record<string, IntakeSelection> {\n  if (typeof cfg !== 'object' || cfg === null) return false;\n  return Object.values(cfg).every(v => typeof v === 'object' && v !== null && typeof (v as { id?: unknown }).id === 'string');\n}\nif (!isValidIntakeConfig(draftConfig)) throw new Error('Intake selections must map keys to { id: string }');","typeGuard":"function isIntakeSelection(v: unknown): v is IntakeSelection {\n  return typeof v === 'object' && v !== null && typeof (v as { id?: unknown }).id === 'string';\n}","tryCatchPattern":"try {\n  await saveIntakeConfig(baseUrl, config);\n} catch (err) {\n  const msg = err instanceof Error ? err.message : String(err);\n  if (/401|403/.test(msg)) promptLogin();\n  else if (/400/.test(msg)) showValidationBanner(msg);\n  else showRetryOption(msg);\n}","preventionTips":["Normalize drafts with normalizeIntakeConfig before saving","Run normalizeIntakeConfig on all fetched configs so stale server data cannot poison the UI","Re-check session validity before writes (401s are most common on save)","Keep the IntakeSelection type as the single shared contract between client and server"],"tags":["http","api","intake-config"],"backgroundTag":"http-request-failed-with-status","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}