mastra-ai/mastra · error · HTTPException
apiError.message || defaultMessage (fallback handler error)
Error message
apiError.message || defaultMessage (fallback handler error)
What it means
This is the fallback branch of handleError: when the thrown error is not one of the recognized special cases, it is cast to ApiError and rethrown as HTTPException using apiError.status or apiError.details.status (defaulting to 500), with apiError.message or the caller-supplied defaultMessage. The library throws this to give every unhandled handler error a consistent HTTP shape while preserving the original message, stack, and cause.
Source
Thrown at packages/server/src/server/handlers/error.ts:136
message: error.message,
stack: error.stack,
cause: error,
});
}
if (isWorkflowSchemaValidationError(error)) {
throw new HTTPException(400, {
message: error.message,
stack: error.stack,
cause: error,
});
}
const apiError = error as ApiError;
const apiErrorStatus = apiError.status || apiError.details?.status || 500;
throw new HTTPException(apiErrorStatus as StatusCode, {
message: apiError.message || defaultMessage,
stack: apiError.stack,
cause: apiError.cause,
});
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Check the response status and message; if it's 500, inspect server logs and the error.cause for the underlying fault.
- Ensure code that intends a specific HTTP status throws errors with a `status` (or `details.status`) property so the correct code is preserved.
- Always throw Error instances with a meaningful message instead of strings or bare objects, so clients get actionable text rather than defaultMessage.
- If a recognized error is being misclassified, verify its identifying fields (code / id) are set as handleError expects.
Example fix
// before: thrown string becomes a generic 500 with defaultMessage
throw 'run failed';
// after: throw a structured ApiError with status and message
const err = new Error('run failed: model unavailable') as Error & { status: number };
err.status = 503;
throw err; Defensive patterns
Strategy: try-catch
Type guard
function hasStatus(e: unknown): e is Error & { status: number } {
return e instanceof Error && typeof (e as any).status === 'number';
} Try / catch
try {
const actions = await listAgentBuilderActions();
} catch (e) {
const status = (e as any)?.status ?? (e as any)?.details?.status ?? 500;
if (status >= 500) {
logError('server fault in agent-builder route', { cause: (e as any)?.cause });
return retryWithBackoff(() => listAgentBuilderActions());
}
throw e;
} Prevention
- Always throw Error objects with a message and an explicit status for intended HTTP codes.
- Attach `cause` when rethrowing so server logs and clients can trace the root fault.
- Monitor 500 rates on agent-builder routes; an unclassified error usually means a missing branch in handleError.
When it happens
Trigger: Any of the agent-builder routes (LIST/GET actions, LIST/GET runs, CREATE run, STREAM run) throws an unrecognized Error; or an ApiError without a message is thrown so the route's defaultMessage is used.
Common situations: An upstream/core error without a status surfaces as an opaque 500; a thrown string or non-Error object has no .message so the generic defaultMessage is returned; storage or network failures inside a handler bubble up unclassified.
Related errors
- AcpAgent does not support resuming suspended generate calls
- AcpAgent does not support resuming suspended stream calls
- ACP prompt stopped before completing: ${response.stopReason}
- ClaudeSDKAgent resumeData must include a message.
- Token exchange failed: ${error}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/42819e13d66c9dd5.
Report an issue: GitHub.