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.

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)

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.