GitbookIO/gitbook · error · Error

useAIChatController must be used within an AIChatProvider

Error message

useAIChatController must be used within an AIChatProvider

What it means

Thrown by useAIChatController(), which reads an AIChatController from the AIChatControllerContext React context. If no ancestor rendered the component that supplies the controller (the AIChatProvider-equivalent), useContext returns null and the hook throws, mirroring the standard React 'used outside provider' pattern.

Source

Thrown at packages/gitbook/src/components/AI/useAIChat.tsx:841

        onCancelQueuedMessage,
        onEvent,
    ]);

    return (
        <AIChatControllerContext.Provider value={controller}>
            {children}
        </AIChatControllerContext.Provider>
    );
}

/**
 * Get the controller to interact with the AI chat.
 * Integrates with search state to synchronize ?ask= parameter.
 */
export function useAIChatController(): AIChatController {
    const controller = React.useContext(AIChatControllerContext);
    if (!controller) {
        throw new Error('useAIChatController must be used within an AIChatProvider');
    }
    return controller;
}

export function getAIChatStatus(chat: AIChatState): AIChatStatus {
    if (chat.error) {
        return 'error';
    }

    if (chat.control) {
        return 'confirm';
    }

    if (chat.responding) {
        const latestMessage = getLatestAssistantMessage(chat.messages);
        const phase = latestMessage?.activity?.currentPhase;
        switch (phase) {
            case AIMessageStepPhase.Commentary:

View on GitHub (pinned to db67585ee2)

Solutions

  1. Move the consuming component inside the component tree that provides AIChatControllerContext (the shipped AI chat root component).
  2. Alternatively, create the controller yourself with the underlying hook that builds it and pass it via your own provider/context.
  3. In tests/Storybook, wrap the consumer in the provider or a fixture that supplies a stub controller.
  4. Audit the component tree (React DevTools) to confirm the provider is an ancestor of every useAIChatController call site.

Example fix

// before
export function ChatInputBar() {
    const controller = useAIChatController(); // throws: rendered outside chat tree
}

// after
// place ChatInputBar inside the chat provider subtree:
<AIChat>
    <ChatInputBar /> {/* now a descendant of AIChatControllerContext.Provider */}
</AIChat>
Defensive patterns

Strategy: type-guard

Validate before calling

// Structurally guarantee the consumer is inside the chat provider tree:
<AIChat>
    <CustomChatInput /> {/* useAIChatController is safe here */}
</AIChat>

Type guard

function useOptionalAIChatController(): AIChatController | null {
    return React.useContext(AIChatControllerContext);
}

// then:
const controller = useOptionalAIChatController();
if (!controller) return null;

Prevention

When it happens

Trigger: Calling useAIChatController() in a component not descended from the chat provider that sets AIChatControllerContext; using the controller hook in a header/prompt bar component that lives outside the chat subtree; rendering in isolation (Storybook/tests) without the provider wrapper; accessing the controller during SSR before the provider mounted is not the issue — it is purely tree structure.

Common situations: Building custom chat UI pieces (input bars, suggestion chips) placed outside the shipped chat component tree; refactoring that moved the consumer above the provider; test renders without the provider wrapper.

Related errors


AI-assisted analysis of GitbookIO/gitbook@db67585ee2 (2026-08-28). Data as JSON: /api/errors/c29cb98d0edf429a. Report an issue: GitHub.