medusajs/medusa · warning
setLocale is not available in the server environment. Please
Error message
setLocale is not available in the server environment. Please set the locale directly through the 'x-medusa-locale' header.
What it means
The JS SDK's setLocale persists the locale in the browser's localStorage so subsequent requests send x-medusa-locale. It checks for the `window` global; when the SDK runs server-side (SSR, Next.js server components, scripts) there is no window and the call just logs this warning and returns without doing anything — no request is made and no error is thrown.
Source
Thrown at packages/core/js-sdk/src/client.ts:173
info: console.info,
debug: console.debug,
}
this.logger = {
...logger,
debug: config.debug ? logger.debug : () => {},
}
if (hasStorage("localStorage")) {
this.locale_ = window.localStorage.getItem(LOCALE_STORAGE_KEY) || ""
}
this.fetch_ = this.initClient()
}
setLocale(locale: string) {
if (!window) {
this.logger.warn(
"setLocale is not available in the server environment. Please set the locale directly through the 'x-medusa-locale' header."
)
return
}
if (hasStorage("localStorage")) {
window.localStorage.setItem(LOCALE_STORAGE_KEY, locale)
}
this.locale_ = locale
}
/**
* `fetch` closely follows (and uses under the hood) the native `fetch` API. There are, however, few key differences:
* - Non 2xx statuses throw a `FetchError` with the status code as the `status` property, rather than resolving the promise
* - You can pass `body` and `query` as objects, and they will be encoded and stringified.
* - The response gets parsed as JSON if the `accept` header is set to `application/json`, otherwise the raw Response object is returned
*View on GitHub (pinned to 5e06e544a2)
Solutions
- Pass the locale per request instead: configure the SDK fetch client to send the 'x-medusa-locale' header on the server
- Move setLocale calls into client-only code (useEffect, onClick handlers, or components guarded by typeof window !== 'undefined')
- Create separate SDK instances for server code with publishable key + custom headers, and keep the localStorage-based one for the browser
Example fix
// before
export const sdk = medusaSdk(...)
sdk.setLocale(locale) // runs in Next.js server component
// after (server)
const sdk = new Client({ baseUrl, publishableKey, customHeaders: { "x-medusa-locale": locale } })
// after (client-only)
useEffect(() => { sdk.setLocale(locale) }, [locale]) Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof window !== "undefined") {
sdk.setLocale(locale)
} else {
// pass header per request instead
client.setFetch((url, init) => fetch(url, { ...init, headers: { ...init?.headers, "x-medusa-locale": locale } }))
} Type guard
const isBrowser = (): boolean => typeof window !== "undefined"
Prevention
- Never call client-only SDK helpers during SSR/module init
- Keep one browser SDK instance and one server instance with explicit headers
- Send x-medusa-locale explicitly in server-side requests
When it happens
Trigger: Calling sdk.setLocale('de') in code that executes in a Node/server runtime: getServerSideProps, Next.js server components, route handlers, unit tests, or SSR rendering of a storefront.
Common situations: Calling setLocale at module top-level of a component that is also server-rendered; shared SDK initialization code imported by both server and client bundles; SSR frameworks hydrating a component that calls setLocale during render.
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/78b97bb270e24a32.
Report an issue: GitHub.