python/cpython · error · ValueError

locale changed during initialization

Error message

locale changed during initialization

What it means

ValueError from the LocaleTime constructor in Lib/_strptime.py. The object snapshots the locale (via _getlang()) at the start of __init__, then computes weekday/month names, AM/PM, alt digits, timezone and date/time formats; if the locale changed underneath it during that sequence (checked by comparing _getlang() before and after), the cached tables would be inconsistent, so it raises 'locale changed during initialization'. The companion check below it covers timezone changes.

Source

Thrown at Lib/_strptime.py:115

        the other thread is still running.  Proper coding would call for
        locks to prevent changing the locale while locale-dependent code is
        running.  The check here is done in case someone does not think about
        doing this.

        Only other possible issue is if someone changed the timezone and did
        not call tz.tzset .  That is an issue for the programmer, though,
        since changing the timezone is worthless without that call.

        """
        self.lang = _getlang()
        self.__calc_weekday()
        self.__calc_month()
        self.__calc_am_pm()
        self.__calc_alt_digits()
        self.__calc_timezone()
        self.__calc_date_time()
        if _getlang() != self.lang:
            raise ValueError("locale changed during initialization")
        if time.tzname != self.tzname or time.daylight != self.daylight:
            raise ValueError("timezone changed during initialization")

    def __calc_weekday(self):
        # Set self.a_weekday and self.f_weekday using the calendar
        # module.
        a_weekday = [calendar.day_abbr[i].lower() for i in range(7)]
        f_weekday = [calendar.day_name[i].lower() for i in range(7)]
        self.a_weekday = a_weekday
        self.f_weekday = f_weekday

    def __calc_month(self):
        # Set self.f_month and self.a_month using the calendar module.
        a_month = [calendar.month_abbr[i].lower() for i in range(13)]
        f_month = [calendar.month_name[i].lower() for i in range(13)]
        self.a_month = a_month
        self.f_month = f_month

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Set the locale once at process startup, before spawning threads that use strptime; never call setlocale per request.
  2. On the next strptime call after the locale settles, _strptime rebuilds LocaleTime automatically — so simply retrying strptime after the race window usually succeeds.
  3. Wrap concurrent locale changes and strptime users with a lock, or pin LC_TIME to 'C' if localized parsing is not needed.

Example fix

# before (race: thread A) locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
#              (thread B) time.strptime(d, '%B %d, %Y')  -> ValueError

# after
# main thread, before starting workers:
import locale
locale.setlocale(locale.LC_ALL, '')   # set once, then never again
Defensive patterns

Strategy: retry

Validate before calling

import locale, threading

_locale_lock = threading.Lock()

def setlocale_safe(category, value):
    with _locale_lock:
        locale.setlocale(category, value)

Try / catch

import time

def strptime_stable(fmt, s, attempts=3):
    for _ in range(attempts):
        try:
            return time.strptime(s, fmt)
        except ValueError as e:
            if 'locale changed' in str(e) or 'timezone changed' in str(e):
                continue
            raise
    raise

Prevention

When it happens

Trigger: One thread calls time.strptime (which lazily builds/caches LocaleTime) while another thread calls locale.setlocale() concurrently; also embedding scenarios where a C extension or signal handler mutates locale mid-construction. The check compares the language code before vs after the six __calc_* passes.

Common situations: Multithreaded apps that call locale.setlocale(locale.LC_ALL, '') per-request (common after porting to mod_wsgi/gunicorn or when a dependency like matplotlib/gettext changes locale); first strptime call racing with startup locale configuration; tests that flip locales without locks.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/c0cc894497110754. Report an issue: GitHub.