{"record":{"id":"ac04203872f0201e","repo":"facebook/docusaurus","slug":"hook-is-called-outside-the-blogpostprovider","errorCode":null,"errorMessage":"Hook is called outside the <BlogPostProvider>. ","messagePattern":"Hook is called outside the <BlogPostProvider>\\. ","errorType":"exception","errorClass":"ReactContextError","httpStatus":null,"severity":"error","filePath":"packages/docusaurus-plugin-content-blog/src/client/contexts.tsx","lineNumber":92,"sourceCode":"  children: ReactNode;\n  content: PropBlogPostContent;\n  isBlogPostPage?: boolean;\n}): ReactNode {\n  const contextValue = useContextValue({content, isBlogPostPage});\n  return <Context.Provider value={contextValue}>{children}</Context.Provider>;\n}\n\n/**\n * Returns the data of the currently browsed blog post. Gives access to\n * front matter, metadata, TOC, etc.\n * When swizzling a low-level component (e.g. the \"Edit this page\" link)\n * and you need some extra metadata, you don't have to drill the props\n * all the way through the component tree: simply use this hook instead.\n */\nexport function useBlogPost(): BlogPostContextValue {\n  const blogPost = useContext(Context);\n  if (blogPost === null) {\n    throw new ReactContextError('BlogPostProvider');\n  }\n  return blogPost;\n}\n","sourceCodeStart":74,"sourceCodeEnd":96,"githubUrl":"https://github.com/facebook/docusaurus/blob/3f483e80e326cc646b54b83d564b3f0c4881b9a6/packages/docusaurus-plugin-content-blog/src/client/contexts.tsx#L74-L96","documentation":"Thrown by useBlogPost() when the React Context it reads (BlogPostContext) is still its default null value, meaning no <BlogPostProvider> ancestor rendered above the component. The message is built by ReactContextError, which interpolates the calling hook's name from the stack trace, producing 'Hook useBlogPost is called outside the <BlogPostProvider>.'. BlogPostProvider is rendered by the blog post theme components; calling useBlogPost outside that subtree is a component-tree placement error.","triggerScenarios":"Calling useBlogPost() in a navbar/footer/layout component that is not under BlogPostProvider; swizzling a low-level component and using it on a non-blog-post page; rendering a blog-post-only subcomponent inside a docs or page layout.","commonSituations":"Swizzling 'BlogPostItem' internals and reusing them in a list header that lacks the provider; an ErrorBoundary swallowing the provider during a render error so children re-render without context; importing a blog-post component into a custom MDX page.","solutions":["Move the useBlogPost() call (or the component using it) to be a descendant of a <BlogPostProvider>.","If you need blog-post data in a component used in multiple contexts, thread the data via props instead of the hook, or conditionally render only on blog post routes.","Wrap a test/storybook render in <BlogPostProvider content={...}> so the context is populated.","Check that a swizzle did not remove the BlogPostProvider wrapper from the post template."],"exampleFix":"// before: component used outside the provider tree\nfunction EditThisPage() {\n  const { metadata } = useBlogPost(); // throws if not under BlogPostProvider\n}\n// after: render it inside the post template that wraps with BlogPostProvider\n<BlogPostProvider content={content} isBlogPostPage>\n  <EditThisPage />\n</BlogPostProvider>","handlingStrategy":"validation","validationCode":"import {useContext} from 'react';\nimport {Context as BlogPostContext} from '@docusaurus/plugin-content-blog/client';\n\nfunction useOptionalBlogPost() {\n  const ctx = useContext(BlogPostContext);\n  return ctx; // null => no provider; consumer decides\n}\n\n// const post = useOptionalBlogPost(); if (!post) return null;","typeGuard":"const isInsideBlogPostProvider = (ctx: unknown): ctx is NonNullable<typeof ctx> =>\n  ctx !== null;","tryCatchPattern":"// Wrap the subtree in an ErrorBoundary that renders a fallback\n// if a component is rendered outside BlogPostProvider by mistake.\nclass SafeBoundary extends React.Component<{}, {hasError: boolean}> {\n  state = {hasError: false};\n  static getDerivedStateFromError() { return {hasError: true}; }\n  render() { return this.state.hasError ? null : this.props.children; }\n}","preventionTips":["Only render blog-post hooks/components under <BlogPostProvider>.","Keep swizzled BlogPostItem children inside the provider wrapper.","Wrap shared components in an ErrorBoundary to fail soft instead of crashing the page."],"tags":["react-hook","blog","react-context","swizzle"],"backgroundTag":null,"analyzedSha":"3f483e80e326cc646b54b83d564b3f0c4881b9a6","analyzedAt":"2026-08-12T13:25:04.382Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}