{"record":{"id":"271f8b7bf4acf538","repo":"shadcn-ui/ui","slug":"useblockviewer-must-be-used-within-a-blockviewerpr","errorCode":null,"errorMessage":"useBlockViewer must be used within a BlockViewerProvider.","messagePattern":"useBlockViewer must be used within a BlockViewerProvider\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/v4/components/block-viewer.tsx","lineNumber":87,"sourceCode":"  activeFile: string | null\n  setActiveFile: (file: string) => void\n  resizablePanelRef: React.RefObject<PanelImperativeHandle | null> | null\n  tree: ReturnType<typeof createFileTreeForRegistryItemFiles> | null\n  highlightedFiles:\n    | (z.infer<typeof registryItemFileSchema> & {\n        highlightedContent: string\n      })[]\n    | null\n  iframeKey?: number\n  setIframeKey?: React.Dispatch<React.SetStateAction<number>>\n}\n\nconst BlockViewerContext = React.createContext<BlockViewerContext | null>(null)\n\nfunction useBlockViewer() {\n  const context = React.useContext(BlockViewerContext)\n  if (!context) {\n    throw new Error(\"useBlockViewer must be used within a BlockViewerProvider.\")\n  }\n  return context\n}\n\nfunction BlockViewerProvider({\n  item,\n  tree,\n  highlightedFiles,\n  children,\n}: Pick<BlockViewerContext, \"item\" | \"tree\" | \"highlightedFiles\"> & {\n  children: React.ReactNode\n}) {\n  const [view, setView] = React.useState<BlockViewerContext[\"view\"]>(\"preview\")\n  const [activeFile, setActiveFile] = React.useState<\n    BlockViewerContext[\"activeFile\"]\n  >(highlightedFiles?.[0].target ?? null)\n  const resizablePanelRef = React.useRef<PanelImperativeHandle>(null)\n  const [iframeKey, setIframeKey] = React.useState(0)","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/shadcn-ui/ui/blob/efac5987074af84ece57c367c6dd83387b967022/apps/v4/components/block-viewer.tsx#L69-L105","documentation":"`useBlockViewer` reads `BlockViewerContext` (`createContext<BlockViewerContext | null>(null)`). `BlockViewerProvider` supplies `item`, `tree`, `highlightedFiles`, plus state (`iframeKey`, etc.). Any consumer for which `useContext` returns null throws — the block viewer sub-components (file tree, code view, iframe) all assume these props exist.","triggerScenarios":"Rendering a block-viewer child (e.g. `<BlockViewerFiles />`, `<BlockViewerIframe />`) outside `<BlockViewerProvider item={...} tree={...} highlightedFiles={...}>`. Common when composing the viewer from parts without the provider, or rendering a single part in isolation.","commonSituations":"Splitting the block viewer into composable parts; rendering a part inside a portal detached from the provider tree; storybook stories of individual parts.","solutions":["Always mount `<BlockViewerProvider item tree highlightedFiles>` above any sub-component that calls `useBlockViewer()`.","Pass the required props (`item`, `tree`, `highlightedFiles`) to the provider — it does not default them.","In tests/stories, render the whole `<BlockViewerProvider>` wrapper with stub props."],"exampleFix":"// before\n<BlockViewerFiles />\n\n// after\n<BlockViewerProvider item={item} tree={tree} highlightedFiles={files}>\n  <BlockViewerFiles />\n</BlockViewerProvider>","handlingStrategy":"type-guard","validationCode":"render(<BlockViewerProvider item={stubItem} tree={stubTree} highlightedFiles={stubFiles}>{<BlockViewerFiles/>}</BlockViewerProvider>)","typeGuard":"import React from \"react\"\nimport { BlockViewerContext } from \"@/components/block-viewer\"\nconst hasBlockViewer = () => React.useContext(BlockViewerContext) != null","tryCatchPattern":"try { useBlockViewer() } catch (e) { if (e.message.includes(\"BlockViewerProvider\")) {/*mount with required props*/} throw e }","preventionTips":["Always pass item/tree/highlightedFiles to BlockViewerProvider — they are required.","Render block-viewer parts only inside the provider subtree.","Provide stub fixtures for tests/stories."],"tags":["react","context","hooks","shadcn-v4","block-viewer"],"backgroundTag":null,"analyzedSha":"efac5987074af84ece57c367c6dd83387b967022","analyzedAt":"2026-08-12T05:00:50.218Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}