mastra-ai/mastra · error · HTTPException
apiError.message || defaultMessage
Error message
apiError.message || defaultMessage
What it means
handleError normalizes any thrown value in a server handler into an HTTPException. It casts the error to ApiError and uses its message, falling back to the defaultMessage passed by the caller; the resulting message shown is apiError.message || defaultMessage with status defaulting to 500. This is the deployer server's consistent error translation layer.
Source
Thrown at packages/deployer/src/server/handlers/error.ts:10
import type { Context } from 'hono';
import { HTTPException } from 'hono/http-exception';
import type { ContentfulStatusCode } from 'hono/utils/http-status';
import type { ApiError } from '../types';
// Helper to handle errors consistently
export function handleError(error: unknown, defaultMessage: string): Promise<Response> {
const apiError = error as ApiError;
throw new HTTPException((apiError.status || 500) as ContentfulStatusCode, {
message: apiError.message || defaultMessage,
cause: apiError.cause,
});
}
export function errorHandler(err: Error, c: Context, isDev?: boolean): Response {
if (err instanceof HTTPException) {
if (isDev) {
return c.json({ error: err.message, cause: err.cause, stack: err.stack }, err.status);
}
return c.json({ error: err.message }, err.status);
}
c.get('mastra').getLogger().error(err);
return c.json({ error: 'Internal Server Error' }, 500);
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Inspect the response body message: if it is the defaultMessage, the original error had no message — check server logs for the real cause.
- For restart endpoints, verify the workflow run id exists and storage is reachable before retrying.
- Throw typed ApiError-shaped errors (with status and message) from custom handlers to control the returned status code.
Example fix
// before
throw new Error(); // no message -> 500 + defaultMessage
// after
throw Object.assign(new Error('Workflow run not found'), { status: 404 }); Defensive patterns
Strategy: type-guard
Type guard
function isApiError(e: unknown): e is { status?: number; message?: string; cause?: unknown } {
return typeof e === 'object' && e !== null && ('status' in e || 'message' in e);
} Try / catch
try {
const res = await fetch('/api/workflows/runs/restart', { method: 'POST', body });
if (!res.ok) {
const { message } = await res.json();
throw new Error(message || `Request failed with ${res.status}`);
}
} catch (e) {
if (e instanceof HTTPException) {
console.error(`Server error ${e.status}: ${e.message}`);
}
throw e;
} Prevention
- Throw errors with explicit status and message properties in custom handlers
- Log the cause server-side; the client may only see the defaultMessage
- Check storage connectivity when restart/run endpoints return 500
When it happens
Trigger: Any handler (e.g. restartAllActiveWorkflowRunsHandler) throws a non-HTTP error, or throws an object without a message/status; handleError converts it — with status undefined becoming 500 and message undefined becoming the handler's defaultMessage.
Common situations: Workflow restart fails because the workflow run no longer exists in storage; storage/connection errors inside handlers; an error thrown without a message property reaching the API surface as a 500.
Related errors
- JSON.stringify(errorResponse)
- error.message
- error.message (MastraError rethrown with mapped status in AI
- error.message (MastraError rethrown with mapped status in fa
- AcpAgent does not support resuming suspended generate calls
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/d72a39132779f2b1.
Report an issue: GitHub.