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

  1. Ensure the value passed to toast() is a string (coerce with String(message ?? '') or message?.message for Errors).
  2. If you have an Error, pass error.message rather than the Error object itself.
  3. For rich content, pass an actual JSX element (<span>...</span>) which the wrapper accepts.
  4. 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

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


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