{"record":{"id":"4b97d832bfc0d17e","repo":"mastra-ai/mastra","slug":"message-status","errorCode":null,"errorMessage":"${message}: ${status}","messagePattern":"\\$\\{message\\}: \\$\\{status\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/auth/client.ts","lineNumber":45,"sourceCode":"}\n\nexport const MASTRA_STUDIO_URL = deriveStudioUrl();\n\nexport const SESSION_EXPIRED_MESSAGE = 'Session expired. Run: mastra auth login';\n\n/**\n * Throw a standardized error for API failures.\n * - 401: \"Session expired\" (authentication failed)\n * - Other: Show the server's error detail or fall back to status code\n */\nexport function throwApiError(message: string, status: number, detail?: string): never {\n  if (status === 401) {\n    throw new Error(SESSION_EXPIRED_MESSAGE);\n  }\n  if (detail) {\n    throw new Error(detail);\n  }\n  throw new Error(`${message}: ${status}`);\n}\n\n/** Best-effort message from platform JSON error bodies (RFC 7807 `detail`, etc.). */\nexport function extractApiErrorDetail(error: unknown): string | undefined {\n  if (!error || typeof error !== 'object') return undefined;\n  const o = error as Record<string, unknown>;\n\n  let detail: string | undefined;\n  if (typeof o.detail === 'string' && o.detail.trim()) detail = o.detail;\n  else if (typeof o.message === 'string' && o.message.trim()) detail = o.message;\n  else if (typeof o.error === 'string' && o.error.trim()) detail = o.error;\n\n  // Validation errors (400) carry the useful part in errors[] — field name plus\n  // message (e.g. the valid-options enum for a bad --region). Without this the\n  // user only sees \"The request body contains invalid fields\".\n  const fieldErrors = Array.isArray(o.errors)\n    ? o.errors\n        .map(e => {","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/cli/src/commands/auth/client.ts#L27-L63","documentation":"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.","triggerScenarios":"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.","commonSituations":"Corporate proxy/gateway returning HTML error pages; platform outage (502/503); rate limiting with empty body (429); network middleware stripping error bodies.","solutions":["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).","Retry the command after waiting if the status is 5xx/429.","Check connectivity/proxy configuration if statuses come from a gateway rather than the platform."],"exampleFix":"// before (shell)\nmastra auth tokens list  # -> 'Failed to list tokens: 502'\n// after\ncurl -s https://status.mastra.ai  # confirm outage, then retry\nmastra auth tokens list","handlingStrategy":"retry","validationCode":"// pre-flight reachability check\nconst res = await fetch(process.env.MASTRA_API_URL ?? 'https://api.mastra.ai', { method: 'HEAD' });\nif (!res.ok && res.status >= 500) throw new Error('Platform unavailable, retry later');","typeGuard":"function isFallbackApiError(err: unknown): err is Error & { message: `${string}: ${number}` } {\n  return err instanceof Error && /: \\d{3}$/.test(err.message);\n}","tryCatchPattern":"try {\n  await fetchProjects(token);\n} catch (err) {\n  if (isFallbackApiError(err) && /: (429|5\\d\\d)$/.test(err.message)) {\n    await new Promise(r => setTimeout(r, 2000));\n    return fetchProjects(token); // one bounded retry\n  }\n  throw err;\n}","preventionTips":["Add bounded retries with backoff for 429/5xx statuses.","Check proxy/gateway configuration (HTTP_PROXY, corporate TLS interception) which often strips error bodies.","Monitor platform status before large automation batches.","Prefer commands that surface server detail (JSON bodies) over gateway-wrapped responses."],"tags":["cli","api","http-status","fallback"],"backgroundTag":"api-error-response","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}