{"record":{"id":"e194ecd620f37105","repo":"vercel/ai","slug":"useuistate-must-be-used-inside-an-ai-provider","errorCode":null,"errorMessage":"`useUIState` must be used inside an <AI> provider.","messagePattern":"`useUIState` must be used inside an <AI> provider\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/rsc/src/shared-client/context.tsx","lineNumber":131,"sourceCode":"          <InternalSyncUIStateProvider.Provider\n            value={clientWrappedSyncUIStateAction}\n          >\n            {children}\n          </InternalSyncUIStateProvider.Provider>\n        </InternalActionProvider.Provider>\n      </InternalUIStateProvider.Provider>\n    </InternalAIStateProvider.Provider>\n  );\n}\n\nexport function useUIState<AI extends AIProvider = any>() {\n  type T = InferUIState<AI, any>;\n\n  const state = React.useContext<\n    [T, (v: T | ((v_: T) => T)) => void] | null | undefined\n  >(InternalUIStateProvider);\n  if (state === null) {\n    throw new Error('`useUIState` must be used inside an <AI> provider.');\n  }\n  if (!Array.isArray(state)) {\n    throw new Error('Invalid state');\n  }\n  if (state[0] === undefined) {\n    throw new Error(\n      '`initialUIState` must be provided to `createAI` or `<AI>`',\n    );\n  }\n  return state;\n}\n\n// TODO: How do we avoid causing a re-render when the AI state changes but you\n// are only listening to a specific key? We need useSES perhaps?\nfunction useAIState<AI extends AIProvider = any>(): [\n  InferAIState<AI, any>,\n  (newState: ValueOrUpdater<InferAIState<AI, any>>) => void,\n];","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/rsc/src/shared-client/context.tsx#L113-L149","documentation":"`useUIState` reads the UI state from React context installed by the `<AI>` provider. When the context value is null there is no provider above the component in the tree, so the hook cannot return a state and the SDK throws instead of failing later with an undefined error.","triggerScenarios":"Calling `useUIState()` in a component rendered without an `<AI>` ancestor — e.g. in a route outside the layout that renders `<AI>`, in a test without the provider, or in a story/portal that escapes the provider tree.","commonSituations":"Moving a component to a new page whose layout doesn't include `<AI>`; rendering children in a React portal mounted outside the provider; unit tests (Vitest/Jest) rendering the component directly; wrapping only part of the app in `<AI>` and using the hook in the unwrapped part.","solutions":["Render the component inside the `<AI>` provider tree (usually via the root layout that exports the `AI` from `createAI`)","Move the `useUIState` call into a child component that is rendered inside `<AI>`","In tests/stories, wrap the component with the `AI` provider before rendering","Verify with React DevTools that `InternalUIStateProvider` context is non-null at the component"],"exampleFix":"// before\nexport default function Page() {\n  const [uiState] = useUIState(); // throws: no provider\n  return <Chat />;\n}\n// after (layout.tsx already renders <AI>)\nexport default function Page() {\n  return <ChatMessages />;\n}\nfunction ChatMessages() {\n  const [uiState] = useUIState();\n  return <div>{uiState.display}</div>;\n}","handlingStrategy":"validation","validationCode":"// component-level guard before calling the hook in dependent code\nfunction isInsideAIProvider(): boolean {\n  return React.useContext(InternalUIStateProvider) != null;\n}","typeGuard":"function hasUIState(\n  v: unknown,\n): v is [T, (v: T | ((v_: T) => T)) => void] {\n  return Array.isArray(v) && v.length === 2;\n}","tryCatchPattern":"let uiState: T | undefined;\ntry {\n  const [value] = useUIState();\n  uiState = value;\n} catch (err) {\n  if (String(err).includes('must be used inside an <AI> provider')) {\n    // render a fallback or rethrow with a clear setup message\n    uiState = undefined;\n  } else {\n    throw err;\n  }\n}","preventionTips":["Render every page/route that uses useUIState under the layout containing <AI>","In tests, always wrap components with the AI provider from createAI","Watch out for portals that escape the provider tree (use context bridging if needed)","Keep the hook call in child components, not in the same file that renders the provider"],"tags":["react-context","rsc","missing-provider","hooks"],"backgroundTag":"missing-provider-context","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}