mastra-ai/mastra · error · Error
useMobileDrawer must be used within a MainSidebarProvider.
Error message
useMobileDrawer must be used within a MainSidebarProvider.
What it means
useMobileDrawer reads only the MobileDrawerContext (openMobile, setOpenMobile), which MainSidebarProvider supplies. Outside the provider the context is null and the hook throws, keeping mobile drawer state accessible only where the provider guarantees it exists.
Source
Thrown at packages/playground-ui/src/ds/components/MainSidebar/main-sidebar-context.ts:62
const ctx = React.useContext(MainSidebarContext);
const drawer = React.useContext(MobileDrawerContext);
if (!ctx || !drawer) {
throw new Error('useMainSidebar must be used within a MainSidebarProvider.');
}
return { ...ctx, ...drawer };
}
export function useMaybeSidebar(): MainSidebarContextValue | null {
const ctx = React.useContext(MainSidebarContext);
const drawer = React.useContext(MobileDrawerContext);
if (!ctx || !drawer) return null;
return { ...ctx, ...drawer };
}
/** Reads only mobile drawer state. Cheap — no re-renders on sidebar resize. */
export function useMobileDrawer(): MobileDrawerContextValue {
const drawer = React.useContext(MobileDrawerContext);
if (!drawer) throw new Error('useMobileDrawer must be used within a MainSidebarProvider.');
return drawer;
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Ensure an ancestor renders <MainSidebarProvider> (it provides both desktop and mobile contexts).
- Alternatively use useMaybeSidebar/useMobileDrawer-nullable variant if the component must tolerate absence.
- Move the provider to the app shell root so headers/footers can consume drawer state.
- Wrap with the provider in tests/storybook before rendering the consumer.
Example fix
// before
function MobileToggle() {
const { openMobile, setOpenMobile } = useMobileDrawer(); // throws
// after
<MainSidebarProvider>
<MobileToggle />
</MainSidebarProvider> Defensive patterns
Strategy: fallback
Validate before calling
// Only call useMobileDrawer under MainSidebarProvider; otherwise fall back: const drawer = useMaybeMobileDrawer?.(); if (!drawer) return <NonCollapsibleHeader />;
Type guard
function hasDrawer(d: MobileDrawerContextValue | null): d is MobileDrawerContextValue {
return d !== null;
} Try / catch
// Catch at the boundary or prefer nullable access:
<ErrorBoundary fallback={<StaticHeader /> }>
<MobileToggle />
</ErrorBoundary> Prevention
- Place headers using drawer state inside the provider's layout subtree.
- Promote MainSidebarProvider to the shell root for app-wide access.
- Wrap isolated renders (tests/storybook) with the provider.
- Prefer nullable context hooks in reusable component libraries.
When it happens
Trigger: Calling useMobileDrawer in a component outside <MainSidebarProvider>; rendering a mobile-only control (e.g. hamburger toggle) in a header laid out above or beside the provider.
Common situations: A header component reused across layouts, some of which don't mount the sidebar provider; tests rendering the toggle in isolation; extracting the drawer toggle into a shared package without the provider dependency.
Related errors
- useMainSidebar must be used within a MainSidebarProvider.
- Comment compounds must be rendered within Comment
- ${componentName} must be used within EnvironmentVariablesEdi
- useJSONSchemaForm must be used within a JSONSchemaForm.Root
- useJSONSchemaFormField must be used within a JSONSchemaForm.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/2bf67191fdbe109e.
Report an issue: GitHub.