marmelab/react-admin · error · Error
Cannot call an event handler while rendering.
Error message
Cannot call an event handler while rendering.
What it means
useDebouncedEvent wraps a callback so it can only be invoked after render, via a ref that is populated in a layout effect. The ref's initial value throws this error, which happens if the debounced handler is invoked during the render phase before React has committed and run the effect.
Solutions
- Move the call into an event handler, useEffect/useLayoutEffect, or async callback instead of render.
- Trigger initial invocations inside useEffect(() => { debouncedFn(); }, []).
- If a value is needed during render, compute it directly instead of calling the debounced handler.
Example fix
// before
const debounced = useDebouncedEvent(fn, 300);
debounced(); // during render -> throws
// after
const debounced = useDebouncedEvent(fn, 300);
React.useEffect(() => { debounced(); }, []); Defensive patterns
Strategy: validation
Validate before calling
// Never call the debounced handler in render; invoke it in an effect:
React.useEffect(() => {
debounced(args);
}, [deps]); Try / catch
try {
debounced(args);
} catch (e) {
if (e instanceof Error && e.message.includes('while rendering')) {
// move invocation to an effect/handler
}
} Prevention
- Treat hook-returned handlers as event/effect-time only.
- Use useEffect for any initial or reactive invocation.
- Enable React strict-mode audits / eslint react-hooks rules to catch render-phase side effects.
When it happens
Trigger: Calling the debounced function directly during a component's render body or inside another component's render (e.g. debounceFn() at the top level of the component function) instead of inside an event handler, effect, or timeout.
Common situations: Developers invoking hooks-returned handlers immediately for 'initial fetch', calling them inside render-time computations, or in class-style lifecycle-like patterns that run during render.
Related errors
- Cannot call an event handler while rendering.
- useCloseNotification must be used within a…
- usePreference cannot be used outside of a Configurable…
- usePreferencesEditor must be used within a…
- useSetInspectorTitle cannot be called outside of a…
AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30).
Data as JSON: /api/errors/e488ff0c05eff60d.
Report an issue: GitHub.
Appendix: source
Thrown at packages/ra-core/src/util/useDebouncedEvent.ts:24
// allow the hook to work in SSR
const useLayoutEffect =
typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
/**
* Hook somewhat equivalent to useEvent, but with a debounce
* Returns a debounced callback which will not change across re-renders unless the
* callback or delay changes
* @see https://reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback
* @see https://github.com/facebook/react/issues/14099#issuecomment-440013892
*/
export const useDebouncedEvent = <Args extends unknown[], Return>(
callback: (...args: Args) => Return,
delay: number
) => {
// Create a ref that stores the debounced callback
const debouncedCallbackRef = useRef<(...args: Args) => Return | undefined>(
() => {
throw new Error('Cannot call an event handler while rendering.');
}
);
// Keep a stable ref to the callback (in case it's an inline function for instance)
const stableCallback = useEvent(callback);
// Whenever callback or delay changes, we need to update the debounced callback
useLayoutEffect(() => {
debouncedCallbackRef.current = debounce(stableCallback, delay);
}, [stableCallback, delay]);
// The function returned by useCallback will invoke the debounced callback
// Its dependencies array is empty, so it never changes across re-renders
return useCallback(
(...args: Args) => debouncedCallbackRef.current(...args),
[]
);
};View on GitHub (pinned to 051f511bb0)