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

  1. Move the component calling useTreeActions()/useTreeSelection() so it is rendered as a child of <TreeView>.
  2. In tests/stories, wrap the consumer in <TreeView items={[...]}>{<YourRow />}</TreeView> (or a minimal TreeView fixture) before rendering.
  3. 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.
  4. 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

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


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/76f1a3483a2abbd5. Report an issue: GitHub.