mastra-ai/mastra · error · Error
Gateway API error ${res.status}: ${body}
Error message
Gateway API error ${res.status}: ${body} What it means
The gateway-memory-client request() helper performs fetch calls against the Mastra Gateway memory API and throws a plain Error (`Gateway API error ${res.status}: ${body}`) whenever the response is not ok, embedding the HTTP status and the raw response body. It is a transport-level guard: any 4xx/5xx from the gateway (auth failures, missing threads, gateway downtime) is surfaced uniformly to the listThreads/getThread/createThread/updateThread/deleteThread/listMessages callers. The error is not typed per status, so callers must parse the message to branch.
Source
Thrown at packages/server/src/server/handlers/gateway-memory-client.ts:98
private async request<T>(path: string, options: RequestInit = {}): Promise<T> {
const url = `${this.baseUrl}${path}`;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10_000);
try {
const res = await fetch(url, {
...options,
signal: options.signal ?? controller.signal,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.apiKey}`,
...((options.headers as Record<string, string>) || {}),
},
});
if (!res.ok) {
const body = await res.text().catch(() => '');
throw new Error(`Gateway API error ${res.status}: ${body}`);
}
return res.json() as Promise<T>;
} finally {
clearTimeout(timeout);
}
}
// ── Threads ──────────────────────────────────────────────────
async listThreads(params: {
resourceId?: string;
limit?: number;
offset?: number;
}): Promise<{ threads: GatewayThread[]; total: number }> {
const query = new URLSearchParams();
if (params.resourceId) query.set('resourceId', params.resourceId);
if (params.limit != null) query.set('limit', String(params.limit));View on GitHub (pinned to 75dd419e61)
Solutions
- Parse the status from the message (regex on 'Gateway API error <status>') and branch: 401/403 fix auth, 404 verify the resource ID, 5xx retry with backoff.
- Verify the gateway base URL and that the gateway service is running and reachable at that URL.
- Check the gateway server logs for the corresponding request; the body in the message usually contains the upstream error detail.
- Confirm client/server versions are compatible (matching mastra versions) so the memory API routes exist.
Example fix
// before: treating all gateway failures the same
try { await client.listThreads(); } catch { alert('failed'); }
// after: branch on the embedded status and retry transient failures
try {
await client.listThreads();
} catch (e) {
const m = /Gateway API error (\d+)/.exec(e.message);
const status = m ? Number(m[1]) : 0;
if (status >= 500 || status === 429) return retryWithBackoff(() => client.listThreads());
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// health-check the gateway before issuing memory calls
const health = await fetch(`${gatewayBaseUrl}/health`);
if (!health.ok) throw new Error(`Gateway unreachable: ${health.status}`); Type guard
function isGatewayApiError(e: unknown): e is Error & { status?: number } {
if (!(e instanceof Error)) return false;
const m = /Gateway API error (\d+)/.exec(e.message);
if (m) (e as any).status = Number(m[1]);
return !!m;
} Try / catch
try {
const threads = await memoryClient.listThreads();
} catch (e) {
if (isGatewayApiError(e)) {
const status = (e as any).status;
if (status === 401 || status === 403) return reauthenticateAndRetry();
if (status === 404) return handleMissingResource(e);
if (status >= 500 || status === 429) return retryWithBackoff(() => memoryClient.listThreads());
}
throw e;
} Prevention
- Add a small wrapper client that parses the status out of the message and attaches it as e.status.
- Retry only transient statuses (429, 5xx) with exponential backoff; never retry 4xx auth/not-found.
- Keep client and gateway mastra versions aligned so memory routes always exist.
- Verify gateway credentials and base URL in each environment's config before deploy.
When it happens
Trigger: Any memory client operation (listThreads, getThread, createThread, updateThread, deleteThread, listMessages) where the gateway responds with a non-ok status, e.g. 401 bad API key, 404 unknown thread/resource ID, 429 rate limit, 5xx gateway failure; also when the response body cannot be read (body defaults to empty string).
Common situations: Expired or wrong gateway credentials; client and gateway version mismatch so an endpoint route no longer exists (404); gateway behind a proxy returning 502/503 during deploys; requesting a thread ID that was deleted from another session.
Related errors
- AZURE_DEPLOYMENTS_FETCH_ERROR
- Slack OAuth HTTP error: ${tokenResponse.status} ${tokenRespo
- Failed to stream background tasks: ${response.statusText}
- Failed to stream agent builder action: ${response.statusText
- Failed to observe agent builder action stream: ${response.st
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/a89edc0170f78d98.
Report an issue: GitHub.