mastra-ai/mastra · error · Error

${message}: ${status}

Error message

${message}: ${status}

What it means

When a platform API call fails with a non-401 status and the response body contains no extractable detail, throwApiError throws `${message}: ${status}`. This is the fallback so the developer at least knows which operation failed and with what HTTP status code.

Source

Thrown at packages/cli/src/commands/auth/client.ts:45

}

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)
    ? o.errors
        .map(e => {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Use the status code to classify: 429 → back off and retry; 5xx → retry later or check platform status; 4xx → inspect the request the CLI made (e.g. `MASTRA_DEBUG=1` or trace with a proxy).
  2. Retry the command after waiting if the status is 5xx/429.
  3. Check connectivity/proxy configuration if statuses come from a gateway rather than the platform.

Example fix

// before (shell)
mastra auth tokens list  # -> 'Failed to list tokens: 502'
// after
curl -s https://status.mastra.ai  # confirm outage, then retry
mastra auth tokens list
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight reachability check
const res = await fetch(process.env.MASTRA_API_URL ?? 'https://api.mastra.ai', { method: 'HEAD' });
if (!res.ok && res.status >= 500) throw new Error('Platform unavailable, retry later');

Type guard

function isFallbackApiError(err: unknown): err is Error & { message: `${string}: ${number}` } {
  return err instanceof Error && /: \d{3}$/.test(err.message);
}

Try / catch

try {
  await fetchProjects(token);
} catch (err) {
  if (isFallbackApiError(err) && /: (429|5\d\d)$/.test(err.message)) {
    await new Promise(r => setTimeout(r, 2000));
    return fetchProjects(token); // one bounded retry
  }
  throw err;
}

Prevention

When it happens

Trigger: Any API wrapper (fetchOrgs, createToken, listTokensAction, revokeTokenAction, fetchProjects) gets a non-401 HTTP error whose body is empty, non-JSON, or lacks a detail field — e.g. a 502 from a proxy or a bare 403 with no body.

Common situations: Corporate proxy/gateway returning HTML error pages; platform outage (502/503); rate limiting with empty body (429); network middleware stripping error bodies.

Related errors


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