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

  1. Wrap the component with <Configurable> (giving it an editor component) so a preference key is injected.
  2. Replace usePreference with useStore(key, defaultValue) if you don't need the Configurable scoping, as the message suggests.
  3. 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

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


AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30). Data as JSON: /api/errors/cd8d544a2fc69779. Report an issue: GitHub.