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

  1. Ensure useDoc() is only called within components rendered under <DocProvider> (the DocPage -> DocProvider subtree).
  2. For components that must work on non-doc pages, use route-aware hooks like useDocsVersion() guarded by useRouteContext(), or pass data via props.
  3. Re-add DocProvider in a swizzled DocPage if you accidentally removed it.
  4. 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

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


AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12). Data as JSON: /api/errors/992534bfd08fdfa3. Report an issue: GitHub.