mastra-ai/mastra · error · RequestError

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

Error message

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

What it means

requestJson is the shared JSON-fetch helper in factory-ui's request.ts. When the response is not ok it builds a message from the server JSON body (`message` then `error`, falling back to `Request failed (${res.status})`) and throws a RequestError carrying the HTTP status. All factory attention, comments, and knowledge-graph calls route through it.

Source

Thrown at mastracode/factory-ui/src/ui/domains/factory/services/request.ts:27

    this.name = 'RequestError';
  }
}

export async function requestJson<T>(url: string, init?: RequestInit): Promise<T> {
  const headers = new Headers(init?.headers);
  if (!headers.has('Accept')) headers.set('Accept', 'application/json');
  if (init?.body && !headers.has('content-type')) headers.set('content-type', 'application/json');
  const res = await fetch(url, { ...init, headers, credentials: 'include' });
  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 RequestError(message, res.status);
  }
  return (await res.json()) as T;
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Catch RequestError specifically and branch on its status property (e.g. 401 -> re-login, 404 -> refresh stale data, 5xx -> retry/backoff).
  2. Read the thrown message for the server-provided `error`/`message` and fix the indicated payload or permission problem.
  3. Ensure cookies are included for cross-origin baseUrl (CORS `Access-Control-Allow-Credentials`) to prevent 401s.
  4. If a 404 on ids, refresh the work item / graph list before retrying since the resource no longer exists.

Example fix

// before
const graph = await fetchKnowledgeGraph(baseUrl);
// after
try {
  const graph = await fetchKnowledgeGraph(baseUrl);
} catch (e) {
  if (e instanceof RequestError && e.status === 401) redirectToLogin();
  else throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: ensure ids the call depends on exist
if (!workItemId) throw new Error('workItemId required before listing comments');
const exists = await res_ok(`${baseUrl}/web/factory/work-items/${encodeURIComponent(workItemId)}`);
if (!exists) throw new Error('Work item no longer exists; refresh the list first');

Type guard

class RequestError extends Error { constructor(message: string, public status: number) { super(message); } }
function isRequestError(e: unknown): e is RequestError {
  return e instanceof RequestError;
}

Try / catch

try {
  const graph = await fetchKnowledgeGraph(baseUrl);
} catch (e) {
  if (isRequestError(e)) {
    if (e.status === 401) redirectToLogin();
    else if (e.status === 404) invalidateAndRefetch();
    else if (e.status >= 500) queueRetryWithBackoff();
    else showSnackbar(e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Any requestJson call (fetchFactoryAttention, updateFactoryAttentionReceipt, listWorkItemComments, fetchKnowledgeGraph, fetchKnowledgeNode) receiving 4xx/5xx: expired session on GET, invalid patch payload on attention updates, unknown work-item id on comments, or knowledge endpoints returning 404/500.

Common situations: Session cookie expired mid-use, work item deleted by another user so comments/knowledge requests 404, malformed update payloads rejected with 400, backend deploy breaking knowledge-graph routes (500), or a proxy returning HTML (non-JSON) so only the generic status message is available.

Related errors


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