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
- Wrap the consuming component tree in <ToolsProvider> (usually at an app/layout level above where useTools is called).
- Check that the component using useTools is actually a descendant of ToolsProvider, including portals and lazy-loaded subtrees.
- 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
- Mount ToolsProvider once at the app root so every route is covered.
- Create a renderWithProviders test helper that always includes ToolsProvider.
- Never call useTools from module scope or plain (non-component) functions.
- Prefer exporting a wrapper component over raw hooks so the provider travels with the feature.
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.