mastra-ai/mastra · error · Error
detail
Error message
detail
What it means
When the platform API returns a non-401 error and the response body includes an error detail (e.g. an RFC 7807 `detail` field), throwApiError rethrows that server-provided detail string verbatim as the Error message. The developer sees the server's own explanation of why the request failed.
Source
Thrown at packages/cli/src/commands/auth/client.ts:43
if (MASTRA_PLATFORM_API_URL.includes('staging')) return 'https://studio.staging.mastra.ai';
return 'https://studio.mastra.ai';
}
export const MASTRA_STUDIO_URL = deriveStudioUrl();
export const SESSION_EXPIRED_MESSAGE = 'Session expired. Run: mastra auth login';
/**
* Throw a standardized error for API failures.
* - 401: "Session expired" (authentication failed)
* - Other: Show the server's error detail or fall back to status code
*/
export function throwApiError(message: string, status: number, detail?: string): never {
if (status === 401) {
throw new Error(SESSION_EXPIRED_MESSAGE);
}
if (detail) {
throw new Error(detail);
}
throw new Error(`${message}: ${status}`);
}
/** Best-effort message from platform JSON error bodies (RFC 7807 `detail`, etc.). */
export function extractApiErrorDetail(error: unknown): string | undefined {
if (!error || typeof error !== 'object') return undefined;
const o = error as Record<string, unknown>;
let detail: string | undefined;
if (typeof o.detail === 'string' && o.detail.trim()) detail = o.detail;
else if (typeof o.message === 'string' && o.message.trim()) detail = o.message;
else if (typeof o.error === 'string' && o.error.trim()) detail = o.error;
// Validation errors (400) carry the useful part in errors[] — field name plus
// message (e.g. the valid-options enum for a bad --region). Without this the
// user only sees "The request body contains invalid fields".
const fieldErrors = Array.isArray(o.errors)View on GitHub (pinned to 75dd419e61)
Solutions
- Read the detail message — it comes directly from the Mastra platform and names the failing constraint.
- Fix the request inputs the detail points to (token id, org id, payload fields).
- Retry after fixing; if detail is a 5xx artifact, retry later or check platform status.
Defensive patterns
Strategy: try-catch
Type guard
function isServerDetailError(err: unknown): err is Error {
return err instanceof Error && !err.message.startsWith('Session expired');
} Try / catch
try {
await createToken(token, name);
} catch (err) {
if (err instanceof Error) {
// message is the server-provided detail; surface it to the user verbatim
console.error(`Request rejected by platform: ${err.message}`);
} else {
throw err;
}
} Prevention
- Validate request payloads (token names, ids) against platform constraints before sending.
- Log full request context when retrying so server details map back to the failing call.
- Treat server detail strings as authoritative — do not string-match on them for control flow, use HTTP status where available.
When it happens
Trigger: fetchOrgs, createToken, listTokensAction, revokeTokenAction, or fetchProjects receives a non-401 HTTP error (400/403/404/409/500) whose JSON body carries a detail/description field; that raw detail string becomes the thrown message.
Common situations: Revoking a token that does not exist (404), creating a token with an invalid name (400), lacking org permissions (403), platform 5xx with a structured error body.
Related errors
- Failed to fetch templates: ${response.statusText}
- request failed with status ${response.status}: ${responseTex
- Perplexity Search request failed with status ${response.stat
- Auth check failed (${res.status})
- Request failed (${response.status}) / server-provided messag
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/f2a94a90280684cd.
Report an issue: GitHub.