marmelab/react-admin · error · Error
usePreference cannot be used outside of a Configurable compo
Error message
usePreference cannot be used outside of a Configurable component. Did you forget to wrap your component with <Configurable>? If you don't want to use Configurable, you can use the useStore hook instead.
What it means
usePreference reads a value from the preferences scoped by the current <Configurable> component; it derives a preference key from usePreferenceKey(). Inside a Configurable subtree the key exists; outside it is empty, and react-admin throws rather than silently reading from an unintended global store. The error message suggests useStore for key/value state without Configurable.
Source
Thrown at packages/ra-core/src/preferences/usePreference.ts:33
function usePreference<T>(
key: string,
defaultValue: T
): [T, (value: T | ((value: T) => void), defaultValue?: T) => void];
function usePreference<T = undefined>(
key: string,
defaultValue?: T | undefined
): [T | undefined, (value: T | ((value: T) => void), defaultValue?: T) => void];
function usePreference(): [
unknown,
(
value: unknown | ((value: unknown) => void),
defaultValue?: unknown
) => void,
];
function usePreference<T>(key = '', defaultValue = undefined) {
const preferenceKey = usePreferenceKey();
if (!preferenceKey) {
throw new Error(
"usePreference cannot be used outside of a Configurable component. Did you forget to wrap your component with <Configurable>? If you don't want to use Configurable, you can use the useStore hook instead."
);
}
return useStore<T>(
preferenceKey && key ? `${preferenceKey}.${key}` : preferenceKey ?? key,
defaultValue
);
}
export { usePreference };
View on GitHub (pinned to 051f511bb0)
Solutions
- Wrap the component with <Configurable> (giving it an editor component) so a preference key is injected.
- Replace usePreference with useStore(key, defaultValue) if you don't need the Configurable scoping, as the message suggests.
- Pass the preference key explicitly through your own context/props if you must read preferences outside the subtree.
Example fix
// before
const PrefValue = () => {
const [value] = usePreference('myKey', 'default'); // throws outside Configurable
return <span>{value}</span>;
};
// after
import { Configurable } from 'react-admin';
<Configurable editor={<MyEditor />} preferenceKey="my-component">
<PrefValue />
</Configurable>;
// or, without Configurable:
const PrefValue = () => {
const [value] = useStore('myKey', 'default');
return <span>{value}</span>;
}; Defensive patterns
Strategy: validation
Validate before calling
import { useContext } from 'react';
import { PreferenceKeyContext } from 'ra-core';
const preferenceKey = useContext(PreferenceKeyContext);
if (!preferenceKey) {
const [value] = useStore('myKey', 'default'); // fallback path
} Type guard
const hasPreferenceKey = (v: string | undefined | null): v is string => typeof v === 'string' && v.length > 0;
Prevention
- Pair every usePreference call with a <Configurable> wrapper in the same component.
- Use useStore when state must work with and without Configurable.
- Never reuse a Configurable child component outside its Configurable subtree.
When it happens
Trigger: Calling usePreference(key, defaultValue) in a component not rendered inside <Configurable>; using it in the editor UI code outside the PreferencesEditor scope; calling it conditionally where the preferenceKey becomes empty at runtime.
Common situations: Reusing a Configurable child component elsewhere in the app (outside Configurable) after extracting it; writing custom inputs for the preferences editor and forgetting the wrapper; migration from useStore to usePreference without adding Configurable.
Related errors
- usePreferencesEditor must be used within a PreferencesEditor
- useSetInspectorTitle cannot be called outside of a Preferenc
- useTranslatableContext must be used inside a TranslatableCon
- useCloseNotification must be used within a CloseNotification
- Cannot call an event handler while rendering.
AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30).
Data as JSON: /api/errors/cd8d544a2fc69779.
Report an issue: GitHub.