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

  1. Check the response status and message; if it's 500, inspect server logs and the error.cause for the underlying fault.
  2. Ensure code that intends a specific HTTP status throws errors with a `status` (or `details.status`) property so the correct code is preserved.
  3. Always throw Error instances with a meaningful message instead of strings or bare objects, so clients get actionable text rather than defaultMessage.
  4. 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

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


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