mastra-ai/mastra · error · Error

${hookName} must be used within MessageScrollerProvider.

Error message

${hookName} must be used within MessageScrollerProvider.

What it means

The MessageScroller design-system component exposes its state through three React contexts (Actions, Scrollable, Visibility), each defaulting to null. Hooks that consume these contexts call useRequiredContext, which throws this error when no MessageScrollerProvider is mounted above the consuming component. It is an intentional programming-contract error: the scroller's actions, scroll state, and visibility APIs only exist once the provider initializes them.

Source

Thrown at packages/playground-ui/src/ds/components/MessageScroller/message-scroller-context.ts:54

export const DEFAULT_SCROLLABLE: MessageScrollerScrollable = { start: false, end: false };
export const DEFAULT_VISIBILITY: MessageScrollerVisibility = { currentAnchorId: undefined, visibleMessageIds: [] };
export const DEFAULT_SCROLL_EDGE_THRESHOLD = 8;
export const DEFAULT_SCROLL_MARGIN = 0;
export const DEFAULT_SCROLL_PREVIOUS_ITEM_PEEK = 64;
export const DEFAULT_REACH_START_THRESHOLD = 160;

// Looser than the edge threshold, which only decides whether the scroll buttons
// are active: how far from the end a reader may sit and still be carried along
// by growing content.
export const AUTO_SCROLL_ATTACH_THRESHOLD = 160;

export const MessageScrollerActionsContext = React.createContext<MessageScrollerActionsContextValue | null>(null);
export const MessageScrollerScrollableContext = React.createContext<MessageScrollerScrollable | null>(null);
export const MessageScrollerVisibilityContext = React.createContext<MessageScrollerVisibility | null>(null);

const useRequiredContext = <TValue>(context: React.Context<TValue | null>, hookName: string) => {
  const value = React.useContext(context);
  if (!value) throw new Error(`${hookName} must be used within MessageScrollerProvider.`);
  return value;
};

export const useRequiredMessageScrollerActionsContext = (hookName: string) =>
  useRequiredContext(MessageScrollerActionsContext, hookName);

export const useRequiredMessageScrollerScrollableContext = (hookName: string) =>
  useRequiredContext(MessageScrollerScrollableContext, hookName);

export const useRequiredMessageScrollerVisibilityContext = (hookName: string) =>
  useRequiredContext(MessageScrollerVisibilityContext, hookName);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Wrap the consuming component tree in <MessageScrollerProvider> so the three contexts are populated.
  2. Move the component calling the hook inside the existing provider's children instead of rendering it as a sibling.
  3. If using a portal, render the portal node inside the provider subtree (React context follows the React tree, not the DOM tree).
  4. Verify you import the hooks from the public module and not re-implement context reads against the raw null-default contexts.

Example fix

// before
export function ScrollToBottomButton() {
  const actions = useRequiredMessageScrollerActionsContext('useMessageScrollerActions');
  return <button onClick={actions.scrollToEnd}>Bottom</button>;
}

// after
export function ChatPanel() {
  return (
    <MessageScrollerProvider>
      <ScrollToBottomButton />
    </MessageScrollerProvider>
  );
}
Defensive patterns

Strategy: validation

Validate before calling

function isInsideMessageScroller(el: HTMLElement | null): boolean {
  return !!el?.closest('[data-message-scroller-root]');
}
// Render scroller-dependent UI only when the provider ancestor exists.

Type guard

const useMaybeMessageScrollerActions = () => {
  const value = React.useContext(MessageScrollerActionsContext);
  return value; // MessageScrollerActionsContextValue | null
};
const hasActions = (v: unknown): v is MessageScrollerActionsContextValue => v != null;

Try / catch

try {
  const actions = useRequiredMessageScrollerActionsContext('useMessageScrollerActions');
  actions.scrollToEnd();
} catch {
  // not inside provider — render fallback/no-op
}

Prevention

When it happens

Trigger: Calling useRequiredMessageScrollerActionsContext, useRequiredMessageScrollerScrollableContext, or useRequiredMessageScrollerVisibilityContext (each passing its own hookName) from a component that is not a descendant of <MessageScrollerProvider>, or rendering the consumer before/outside the provider due to conditional rendering, portals, or wrong import of the context file.

Common situations: Extracting a message-list subcomponent into its own file and forgetting to keep it inside the provider tree; rendering scroller toolbar buttons in a modal or portal that escapes the provider; splitting a page so the provider unmounts while children still reference the hooks; copy-pasting a hook into a storybook story without wrapping in the provider.

Related errors


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