CherryHQ/cherry-studio · error · Error
${name} must be used inside <TreeView />
Error message
${name} must be used inside <TreeView /> What it means
Thrown by the ensure() helper in the TreeView context module when useTreeActions() or useTreeSelection() is called outside of a <TreeView /> component. TreeView provides the TreeActionsContext and TreeSelectionContext via React context; the hooks read those contexts and assert they are non-null. This is the standard React 'context used without provider' guard, mirroring patterns from Radix/Headless UI.
Source
Thrown at packages/ui/src/components/composites/tree-view/contexts.ts:26
*/
export interface TreeActionsContextValue {
toggleExpanded: (id: string) => void
selectNode: (id: string) => void
getDragHandleProps: (id: string) => TreeDragHandleProps
}
export interface TreeSelectionContextValue {
expandedIds: ReadonlySet<string>
selectedId: string | null
}
export const TreeActionsContext = createContext<TreeActionsContextValue | null>(null)
export const TreeSelectionContext = createContext<TreeSelectionContextValue | null>(null)
function ensure<T>(value: T | null, name: string): T {
if (value === null) {
throw new Error(`${name} must be used inside <TreeView />`)
}
return value
}
export function useTreeActions(): TreeActionsContextValue {
return ensure(use(TreeActionsContext), 'useTreeActions')
}
export function useTreeSelection(): TreeSelectionContextValue {
return ensure(use(TreeSelectionContext), 'useTreeSelection')
}
View on GitHub (pinned to 726446b54c)
Solutions
- Move the component calling useTreeActions()/useTreeSelection() so it is rendered as a child of <TreeView>.
- In tests/stories, wrap the consumer in <TreeView items={[...]}>{<YourRow />}</TreeView> (or a minimal TreeView fixture) before rendering.
- If you need tree state in a sibling (e.g. an external toolbar), lift that state up and pass it via props, or expose a controlled API on TreeView rather than calling the internal hook.
- Check the component tree with React DevTools to confirm the provider is an ancestor of the consumer.
Example fix
// before
function Toolbar() {
const { selectNode } = useTreeActions() // throws: not inside TreeView
return <button onClick={() => selectNode('x')}>select</button>
}
<TreeView .../>
<Toolbar />
// after
<TreeView ...>
<Toolbar />
</TreeView> Defensive patterns
Strategy: type-guard
Prevention
- Always render TreeView subcomponents (anything calling useTreeActions/useTreeSelection) as descendants of <TreeView>.
- In tests/stories, wrap isolated row components in a <TreeView> fixture before rendering.
- If you need tree actions outside the tree, expose a controlled callback prop on TreeView instead of calling the internal hook.
- Use React DevTools to confirm the provider is an ancestor before debugging missing-context errors.
When it happens
Trigger: Rendering a TreeRow, TreeItem, or any custom component that calls useTreeActions()/useTreeSelection() as a sibling of <TreeView> rather than a descendant. Also triggered when a TreeView subcomponent is extracted into a story/test (e.g. Storybook, React Testing Library) without wrapping it in <TreeView>, or when conditional rendering accidentally renders the consumer above the provider in the tree.
Common situations: Writing a unit test for a single tree row component in isolation; copy-pasting a row renderer outside the tree; refactoring that moves a hook call into a wrapper component rendered alongside (not inside) TreeView; using the hook in a toolbar that lives outside the tree container.
Related errors
- useImagePreviewTransform requires zoomStep > 0
- Provider extension "${providerId}" not registered
- [theme-contract] renderer TypeScript source ${fileName} cann
- [theme-contract] renderer TypeScript source ${fileName} cann
- useImagePreviewTransform requires minZoom <= maxZoom
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/76f1a3483a2abbd5.
Report an issue: GitHub.