nocobase/nocobase · error · Error

useTools must be used within a ToolsProvider

Error message

useTools must be used within a ToolsProvider

What it means

useTools is a React hook that reads ToolsContext via useContext; it throws when the context value is null/undefined, i.e. when no <ToolsProvider> ancestor has rendered. The library deliberately throws instead of returning a null context so consumers fail fast at the point of misuse rather than crashing later on a missing property.

Source

Thrown at packages/core/client-v2/src/ai/tools-manager/hooks/index.ts:16

/**
 * This file is part of the NocoBase (R) project.
 * Copyright (c) 2020-2024 NocoBase Co., Ltd.
 * Authors: NocoBase Team.
 *
 * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
 * For more information, please refer to: https://www.nocobase.com/agreement.
 */

import { useContext } from 'react';
import { ToolsContext } from './context';

export const useTools = () => {
  const ctx = useContext(ToolsContext);
  if (!ctx) {
    throw new Error('useTools must be used within a ToolsProvider');
  }
  return ctx;
};

export * from './context';
export * from './provider';

View on GitHub (pinned to fa42722fef)

Solutions

  1. Wrap the consuming component tree in <ToolsProvider> (usually at an app/layout level above where useTools is called).
  2. Check that the component using useTools is actually a descendant of ToolsProvider, including portals and lazy-loaded subtrees.
  3. In tests, wrap the component with ToolsProvider inside render() (or create a renderWithProviders helper).

Example fix

// before
export default function Panel() {
  const tools = useTools(); // throws
  return null;
}
// after
export default function App() {
  return (
    <ToolsProvider>
      <Panel />
    </ToolsProvider>
  );
}
Defensive patterns

Strategy: try-catch

Validate before calling

const canUseTools = typeof ToolsContext !== 'undefined'; // and ensure provider is mounted above
// in React DevTools or via a check component:
// const ctx = useContext(ToolsContext); if (!ctx) return <ToolsProvider><Child/></ToolsProvider>;

Type guard

function hasToolsContext(ctx: ReturnType<typeof useContext<typeof ToolsContext>> | null): ctx is NonNullable<ReturnType<typeof useContext<typeof ToolsContext>>> {
  return ctx != null;
}

Try / catch

let tools: ToolsContextValue;
try {
  tools = useTools();
} catch {
  return <ToolsProvider><RealComponent /></ToolsProvider>;
}

Prevention

When it happens

Trigger: Calling useTools() from a component rendered outside a <ToolsProvider>, or from module-level/non-React code with no React tree ancestor.

Common situations: A new tool-consuming component is mounted in a route/portal that forgot the provider; a component was moved out of the provider subtree during refactoring; a hook is called in a test with render(<Component/>) without wrapping render in the provider.

Related errors


AI-assisted analysis of nocobase/nocobase@fa42722fef (2026-09-01). Data as JSON: /api/errors/e89162e5cf15bc41. Report an issue: GitHub.