From 0277062fecc278e630bf2110761a545339f6b9fe Mon Sep 17 00:00:00 2001 From: 0xFl4g <35390196+0xFl4g@users.noreply.github.com> Date: Thu, 18 Dec 2025 10:56:18 +0000 Subject: [PATCH] fix(translation): prevent duplicate locale error on server restart (#14345) The translation module's defaults loader throws a warning on every server restart after the first run because the upsert method uses `id` as the unique key, but defaultLocales only contains `code` and `name`. This causes the upsert to always attempt creation, which fails on the unique `code` constraint with: "Locale with code: en-US, already exists." Fix: Fetch existing locales first and map their IDs into defaultLocales so upsert can properly identify existing records and update them. --- .changeset/frank-days-start.md | 5 ++++ .../translation/src/loaders/defaults.ts | 24 +++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 .changeset/frank-days-start.md diff --git a/.changeset/frank-days-start.md b/.changeset/frank-days-start.md new file mode 100644 index 0000000000..02ec1ebd41 --- /dev/null +++ b/.changeset/frank-days-start.md @@ -0,0 +1,5 @@ +--- +"@medusajs/translation": patch +--- + +fix(translation): prevent duplicate locale error on server restart diff --git a/packages/modules/translation/src/loaders/defaults.ts b/packages/modules/translation/src/loaders/defaults.ts index ab05f516f6..1509127908 100644 --- a/packages/modules/translation/src/loaders/defaults.ts +++ b/packages/modules/translation/src/loaders/defaults.ts @@ -3,7 +3,10 @@ import { Logger, ModulesSdkTypes, } from "@medusajs/framework/types" -import { ContainerRegistrationKeys } from "@medusajs/framework/utils" +import { + ContainerRegistrationKeys, + normalizeLocale, +} from "@medusajs/framework/utils" import Locale from "@models/locale" /** @@ -70,7 +73,24 @@ export default async ({ container }: LoaderOptions): Promise => { container.resolve("localeService") try { - const resp = await localeService_.upsert(defaultLocales) + // Fetch existing locales to map their IDs for upsert + // The upsert method uses `id` as the key, so we need to include IDs for existing locales + const existingLocales = await localeService_.list( + {}, + { select: ["id", "code"] } + ) + const existingByCode = new Map( + existingLocales.map((l) => [l.code, l.id]) + ) + + // Map default locales to include IDs for existing ones + const localesToUpsert = defaultLocales.map((locale) => { + const normalizedCode = normalizeLocale(locale.code) + const existingId = existingByCode.get(normalizedCode) + return existingId ? { ...locale, id: existingId } : locale + }) + + const resp = await localeService_.upsert(localesToUpsert) logger.debug(`Loaded ${resp.length} locales`) } catch (error) { logger.warn(