{"record":{"id":"d8561337db610cab","repo":"janhq/jan","slug":"reasoning-components-must-be-used-within-reasoning","errorCode":null,"errorMessage":"Reasoning components must be used within Reasoning","messagePattern":"Reasoning components must be used within Reasoning","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web-app/src/components/ai-elements/reasoning.tsx","lineNumber":34,"sourceCode":"  useMemo,\n  useState,\n} from 'react'\nimport { Streamdown } from 'streamdown'\nimport { Shimmer } from './shimmer'\n\ntype ReasoningContextValue = {\n  isStreaming: boolean\n  isOpen: boolean\n  setIsOpen: (open: boolean) => void\n  duration: number | undefined\n}\n\nconst ReasoningContext = createContext<ReasoningContextValue | null>(null)\n\nexport const useReasoning = () => {\n  const context = useContext(ReasoningContext)\n  if (!context) {\n    throw new Error('Reasoning components must be used within Reasoning')\n  }\n  return context\n}\n\nexport type ReasoningProps = ComponentProps<typeof Collapsible> & {\n  isStreaming?: boolean\n  open?: boolean\n  defaultOpen?: boolean\n  onOpenChange?: (open: boolean) => void\n  duration?: number\n}\n\nconst MS_IN_S = 1000\n\nexport const Reasoning = memo(\n  ({\n    className,\n    isStreaming = false,","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/web-app/src/components/ai-elements/reasoning.tsx#L16-L52","documentation":"useReasoning is a React context hook that reads ReasoningContext, populated only by the Reasoning provider component. When called outside a <Reasoning> ancestor the context is null and the hook throws this Error to surface the misuse immediately.","triggerScenarios":"Calling useReasoning (or rendering ReasoningTrigger/ReasoningContent outside the wrapper) without a <Reasoning> ancestor in the component tree.","commonSituations":"Moving the reasoning toggle or content block into a different parent during refactor; rendering reasoning parts in a message list without the Reasoning wrapper; isolated test/storybook mounting.","solutions":["Wrap the consuming components in <Reasoning> ... </Reasoning>","Ensure ReasoningTrigger and ReasoningContent are children of Reasoning, not siblings","Guard with a non-throwing context hook if usage outside is legitimate","Verify conditional rendering never mounts the consumer without the provider"],"exampleFix":"// before\n<ReasoningTrigger />\n<ReasoningContent /> // thrown: no context\n// after\n<Reasoning isStreaming={isStreaming} duration={duration}>\n  <ReasoningTrigger />\n  <ReasoningContent />\n</Reasoning>","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function useReasoningSafe() {\n  return useContext(ReasoningContext); // null outside provider\n}\n// consumer:\nconst ctx = useReasoningSafe();\nif (ctx === null) throw new Error('Reasoning components must be used within Reasoning');","tryCatchPattern":"try {\n  render(<ReasoningContent />);\n} catch (e) {\n  if (e.message.includes('must be used within Reasoning')) {\n    console.error('JSX error: wrap the component in <Reasoning>');\n  }\n}","preventionTips":["Render ReasoningTrigger/ReasoningContent only inside <Reasoning>","Add a unit test that mounts consumers without a provider and asserts the error","When moving components, verify provider ancestry in the new location","Use a nullable-context helper hook where outside usage is expected"],"tags":["react","context","typescript","hook"],"backgroundTag":"missing-required-context-provider","analyzedSha":"7205d770c1e097c3daf35a911176410e93bc5564","analyzedAt":"2026-09-17T14:27:30.100Z","contentChangedAt":"2026-09-17T14:27:30.100Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}