marmelab/react-admin · error

The i18nProvider returned a Promise for the messages of the…

Error message

The i18nProvider returned a Promise for the messages of the default locale (${initialLocale}). Please update your i18nProvider to return the messages of the default locale in a synchronous way.

What it means

ra-i18n-polyglot's polyglotI18nProvider requires getMessages for the initial (default) locale to return messages synchronously, because it must build the Polyglot instance eagerly at setup time. If the function returns a Promise for the default locale, the provider cannot proceed and throws at creation time.

Solutions

  1. Make getMessages return messages synchronously for the default locale (static import or preloaded object)
  2. Load async locales only for non-default locales, using async/await inside getMessages with a cached synchronous default
  3. Pre-fetch all messages before creating the provider, then use a synchronous getMessages that reads from the cache

Example fix

// before
polyglotI18nProvider(async locale => {
    const messages = await fetch(`/i18n/${locale}.json`).then(r => r.json());
    return messages;
}, 'en');
// after
import en from './i18n/en.json';
const cache = { en };
polyglotI18nProvider(locale => {
    if (cache[locale]) return cache[locale];
    return fetch(`/i18n/${locale}.json`)
        .then(r => r.json())
        .then(messages => { cache[locale] = messages; return messages; });
}, 'en');
Defensive patterns

Strategy: validation

Validate before calling

const getMessages = locale => {
    const messages = cache[locale];
    if (messages instanceof Promise) {
        throw new Error(`getMessages returned a Promise for default locale: ${locale}`);
    }
    return messages;
};

Type guard

const isSyncMessages = (m: unknown): m is Record<string, any> =>
    !(m instanceof Promise) && typeof m === 'object' && m !== null;

Try / catch

try {
    const i18nProvider = polyglotI18nProvider(getMessages, 'en', availableLocales);
} catch (e) {
    if (e instanceof Error && e.message.includes('returned a Promise for the messages')) {
        console.error('Default locale messages must be synchronous; preload translations first');
        throw e;
    }
    throw e;
}

Prevention

When it happens

Trigger: polyglotI18nProvider(locale => fetch(...)...) with the default locale resolved via an async call; passing an async getMessages function whose first invocation (for initialLocale) is asynchronous; using jsonServerProvider-style async message loading for the startup locale.

Common situations: Migrating from a fully async i18n setup; loading translations from an API for all locales including the initial one; mixing static imports for 'en' with dynamic imports for other locales but forgetting to keep the default synchronous.

Related errors


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

Appendix: source

Thrown at packages/ra-i18n-polyglot/src/index.ts:38

 *     fr: frenchMessages,
 *     en: englishMessages,
 * };
 * const i18nProvider = polyglotI18nProvider(
 *     locale => messages[locale],
 *     'en',
 *     [{ locale: 'en', name: 'English' }, { locale: 'fr', name: 'Français' }]
 * )
 */
export default (
    getMessages: GetMessages,
    initialLocale: string = 'en',
    availableLocales: Locale[] | any = [{ locale: 'en', name: 'English' }],
    polyglotOptions: any = {}
): I18nProvider => {
    let locale = initialLocale;
    const messages = getMessages(initialLocale);
    if (messages instanceof Promise) {
        throw new Error(
            `The i18nProvider returned a Promise for the messages of the default locale (${initialLocale}). Please update your i18nProvider to return the messages of the default locale in a synchronous way.`
        );
    }

    let availableLocalesFinal, polyglotOptionsFinal;
    if (Array.isArray(availableLocales)) {
        // third argument is an array of locales
        availableLocalesFinal = availableLocales;
        polyglotOptionsFinal = polyglotOptions;
    } else {
        // third argument is the polyglotOptions
        availableLocalesFinal = [{ locale: 'en', name: 'English' }];
        polyglotOptionsFinal = availableLocales;
    }
    const polyglot = new Polyglot({
        locale,
        phrases: { '': '', ...messages },
        ...polyglotOptionsFinal,

View on GitHub (pinned to 051f511bb0)