mastra-ai/mastra · error
Invalid message type
Error message
Invalid message type
What it means
The playground UI's toast() wrapper accepts a string, an array of strings, or a React element and forwards it to sonner. If the message is none of these (e.g. a plain object, number, null, or undefined), sonner cannot render it safely, so the wrapper throws 'Invalid message type' to surface the programming mistake early instead of showing a broken toast.
Source
Thrown at packages/playground-ui/src/lib/toast.tsx:31
// only built-in dismiss affordance we expose).
export const Toaster = ({ className, toastOptions, ...rest }: ToasterProps) => (
<SonnerToaster
{...rest}
closeButton
richColors
className={cn('mastra-toaster', className)}
toastOptions={{ duration: 5000, ...toastOptions }}
/>
);
// Forward sonner's return value so callers can update/dismiss by id later.
const forEachOrOnce = <M, R>(message: M | M[], emit: (m: M) => R): R | R[] =>
Array.isArray(message) ? message.map(emit) : emit(message);
export const toast = (message: string | string[] | ReactNode, options: ExternalToast = {}) => {
if (Array.isArray(message)) return message.map(m => sonnerToast(m, options));
if (React.isValidElement(message) || typeof message === 'string') return sonnerToast(message, options);
throw new Error('Invalid message type');
};
toast.success = (message: string | string[], options: ExternalToast = {}) =>
forEachOrOnce(message, m => sonnerToast.success(m, options));
toast.error = (message: string | string[], options: ExternalToast = {}) =>
forEachOrOnce(message, m => sonnerToast.error(m, options));
toast.warning = (message: string | string[], options: ExternalToast = {}) =>
forEachOrOnce(message, m => sonnerToast.warning(m, options));
toast.info = (message: string | string[], options: ExternalToast = {}) =>
forEachOrOnce(message, m => sonnerToast.info(m, options));
toast.custom = (message: ReactNode, options: ExternalToast = {}) => sonnerToast(message, options);
toast.dismiss = (toastId?: string | number) => sonnerToast.dismiss(toastId);
toast.promise = <T,>({
myPromise,
loadingMessage,View on GitHub (pinned to 75dd419e61)
Solutions
- Ensure the value passed to toast() is a string (coerce with String(message ?? '') or message?.message for Errors).
- If you have an Error, pass error.message rather than the Error object itself.
- For rich content, pass an actual JSX element (<span>...</span>) which the wrapper accepts.
- Check for undefined coming from optional API fields before calling toast and provide a default message.
Example fix
// before toast(error); // Error object — throws 'Invalid message type' // after toast(error instanceof Error ? error.message : 'Something went wrong');
Defensive patterns
Strategy: type-guard
Type guard
function isValidToastMessage(m: unknown): m is string | string[] | React.ReactElement {
return typeof m === 'string' || Array.isArray(m) || React.isValidElement(m);
} Try / catch
try {
toast(message as string);
} catch (e) {
if (e instanceof Error && e.message === 'Invalid message type') {
toast('Something went wrong'); // safe default
} else throw e;
} Prevention
- Type toast message parameters as string | string[] | ReactNode at call sites.
- Pass error.message, never the Error object itself.
- Default undefined messages: toast(msg ?? 'Operation failed').
When it happens
Trigger: Calling toast(message) where message is neither an array, nor a valid React element, nor a string — most commonly toast(undefined) when a variable holding the message is undefined, toast(err) with an Error object instead of err.message, or toast(someObject).
Common situations: Passing the result of a failed lookup (undefined) as the message, passing an Error/exception object directly rather than its .message, or passing a non-string value like a number or object from an API response.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- Path must include :agentId to route to the correct agent or
- MemoryThread.${methodName}() requires an agentId. Pass it vi
- Unhandled content part type: ${(exhaustiveCheck as { type: s
- ${label} must be a string.
- Plugin entry must be a .ts file
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/87ff7422f6307b78.
Report an issue: GitHub.