facebook/docusaurus · error · ReactContextError
Hook is called outside the <DocProvider>.
Error message
Hook is called outside the <DocProvider>.
What it means
Thrown by useDoc() when DocContext is null, i.e. no <DocProvider> ancestor exists. DocProvider is set up by the docs theme (DocPage) around the rendered doc; calling useDoc outside that subtree (e.g. in a layout, navbar, or on a non-doc route) throws. ReactContextError interpolates the hook name from the stack so the message reads 'Hook useDoc is called outside the <DocProvider>.'.
Source
Thrown at packages/docusaurus-plugin-content-docs/src/client/doc.tsx:68
}: {
children: ReactNode;
content: PropDocContent;
}): ReactNode {
const contextValue = useContextValue(content);
return <Context.Provider value={contextValue}>{children}</Context.Provider>;
}
/**
* Returns the data of the currently browsed doc. Gives access to the doc's MDX
* Component, front matter, metadata, TOC, etc. When swizzling a low-level
* component (e.g. the "Edit this page" link) and you need some extra metadata,
* you don't have to drill the props all the way through the component tree:
* simply use this hook instead.
*/
export function useDoc(): DocContextValue {
const doc = useContext(Context);
if (doc === null) {
throw new ReactContextError('DocProvider');
}
return doc;
}
View on GitHub (pinned to 3f483e80e3)
Solutions
- Ensure useDoc() is only called within components rendered under <DocProvider> (the DocPage -> DocProvider subtree).
- For components that must work on non-doc pages, use route-aware hooks like useDocsVersion() guarded by useRouteContext(), or pass data via props.
- Re-add DocProvider in a swizzled DocPage if you accidentally removed it.
- In tests, wrap renders in a DocProvider with the expected DocContextValue.
Example fix
// before
function EditUrl() {
const { metadata } = useDoc(); // throws on non-doc pages
}
// after: only render within the doc subtree, or guard the route
function EditUrl() {
const route = useRouteContext();
if (route?.plugin.name !== 'docusaurus-plugin-content-docs') return null;
const { metadata } = useDoc();
return <a href={metadata.editUrl}>Edit</a>;
} Defensive patterns
Strategy: validation
Validate before calling
import useRouteContext from '@docusaurus/useRouteContext';
function useIsDocRoute() {
const route = useRouteContext();
return route?.plugin?.name === 'docusaurus-plugin-content-docs';
}
// if (!useIsDocRoute()) return null; // before calling useDoc() Type guard
const isDocRoute = ( route: ReturnType<typeof useRouteContext>, ): boolean => route?.plugin?.name === 'docusaurus-plugin-content-docs';
Prevention
- Keep useDoc() calls within DocPage -> DocProvider subtree.
- Gate shared components on route plugin name before calling doc hooks.
- Re-add DocProvider in any swizzled DocPage.
When it happens
Trigger: Calling useDoc() in a global layout/navbar component rendered on all pages; using a docs-internal component inside a blog or page route; swizzling that removed the DocProvider wrapper from DocPage.
Common situations: Reusing a doc toolbar/sidebar subcomponent in a custom layout; a swizzle of DocPage that drops the provider; importing doc-only components into MDX pages outside the docs plugin.
Related errors
- Hook is called outside the <DocSidebarItemsExpandedStateProv
- Hook is called outside the <DocsPreferredVersionContextProvi
- Hook is called outside the <DocsSidebarProvider>.
- Hook is called outside the <DocsVersionProvider>.
- Hook is called outside the <BlogPostProvider>.
AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12).
Data as JSON: /api/errors/992534bfd08fdfa3.
Report an issue: GitHub.