mastra-ai/mastra · error

Request failed (${res.status}) / server-provided message

Error message

Request failed (${res.status}) / server-provided message

What it means

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.

Source

Thrown at mastracode/factory-ui/src/ui/domains/factory/services/intake.ts:58

  return selection.enabled ? selection : { ...selection, enabled: true };
}

async function requestIntakeConfig(baseUrl: string, init?: RequestInit): Promise<IntakeConfig> {
  const res = await fetch(`${baseUrl}/web/intake/config`, {
    headers: { Accept: 'application/json', ...(init?.body ? { 'content-type': 'application/json' } : {}) },
    credentials: 'include',
    ...init,
  });
  if (!res.ok) {
    let message = `Request failed (${res.status})`;
    try {
      const body = (await res.json()) as { error?: string; message?: string };
      if (body.message) message = body.message;
      else if (body.error) message = body.error;
    } catch {
      /* ignore non-JSON */
    }
    throw new Error(message);
  }
  const { config } = (await res.json()) as { config?: Partial<Record<string, IntakeSelection>> };
  return normalizeIntakeConfig(config);
}

/** Read the caller's intake config (server falls back to the defaults). */
export async function fetchIntakeConfig(baseUrl: string): Promise<IntakeConfig> {
  return requestIntakeConfig(baseUrl);
}

/** Save the caller's intake config; resolves to the persisted config. */
export async function saveIntakeConfig(baseUrl: string, config: IntakeConfig): Promise<IntakeConfig> {
  return requestIntakeConfig(baseUrl, { method: 'PUT', body: JSON.stringify(config) });
}

/** Routing of one intake source to the Factory project its items land in. */
export interface IntakeSourceBinding {
  integrationId: string;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read error.message for the server-provided cause; otherwise use the status code
  2. Re-authenticate if the status is 401/403
  3. For saves, validate intake selection keys/values against the current IntakeSelection schema before calling saveIntakeConfig
  4. If 5xx, retry after the backend is healthy

Example fix

// before
await saveIntakeConfig(baseUrl, { legacyField: { id: 'x' } } as Record<string, IntakeSelection>);
// after
const cfg = normalizeIntakeConfig({ area: { id: 'x' } });
await saveIntakeConfig(baseUrl, cfg);
Defensive patterns

Strategy: validation

Validate before calling

function isValidIntakeConfig(cfg: unknown): cfg is Record<string, IntakeSelection> {
  if (typeof cfg !== 'object' || cfg === null) return false;
  return Object.values(cfg).every(v => typeof v === 'object' && v !== null && typeof (v as { id?: unknown }).id === 'string');
}
if (!isValidIntakeConfig(draftConfig)) throw new Error('Intake selections must map keys to { id: string }');

Type guard

function isIntakeSelection(v: unknown): v is IntakeSelection {
  return typeof v === 'object' && v !== null && typeof (v as { id?: unknown }).id === 'string';
}

Try / catch

try {
  await saveIntakeConfig(baseUrl, config);
} catch (err) {
  const msg = err instanceof Error ? err.message : String(err);
  if (/401|403/.test(msg)) promptLogin();
  else if (/400/.test(msg)) showValidationBanner(msg);
  else showRetryOption(msg);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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