Humanizr/Humanizer · error · InvalidOperationException

Cannot register localisers after the registry has been used.

Error message

Cannot register localisers after the registry has been used.

What it means

Thrown by LocaliserRegistry<T>.Register(string, TLocaliser) when you attempt to register a localiser instance after the registry has already been 'frozen'. Freezing happens lazily on the first ResolveForCulture/ResolveForUiCulture call, which converts the builder dictionary into a FrozenDictionary for fast reads. The registry is immutable after first use; this InvalidOperationException enforces that contract.

Source

Thrown at src/Humanizer/Configuration/LocaliserRegistry.cs:58

    public TLocaliser ResolveForCulture(CultureInfo? culture)
    {
        var cultureInfo = culture ?? CultureInfo.CurrentCulture;
        return cultureSpecificCache.GetValue(
            cultureInfo,
            c => new(FindLocaliser(c)(c))
        ).Value!;
    }

    /// <summary>
    /// Registers the localiser for the culture provided
    /// </summary>
    public void Register(string localeCode, TLocaliser localiser)
    {
        lock (lockObject)
        {
            if (frozenLocalisers != null)
            {
                throw new InvalidOperationException("Cannot register localisers after the registry has been used.");
            }
            localisersBuilder[localeCode] = _ => localiser;
        }
    }

    /// <summary>
    /// Registers the localiser factory for the culture provided
    /// </summary>
    public void Register(string localeCode, Func<CultureInfo, TLocaliser> localiser)
    {
        lock (lockObject)
        {
            if (frozenLocalisers != null)
            {
                throw new InvalidOperationException("Cannot register localisers after the registry has been used.");
            }
            localisersBuilder[localeCode] = localiser;
        }

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Move all Register calls into a single early startup path (Program.Main / a bootstrap extension) before any Humanizer formatting method is invoked.
  2. If you must change localisers per request/test, do not use the shared static registries; construct a standalone LocaliserRegistry<T> instance instead.
  3. Detect the ordering problem by searching for the first ToWords/Humanize/ResolveForCulture call and ensuring all Register calls precede it.

Example fix

// before (bug): first request humanizes, then a module registers late
app.MapGet("/x", () => 1.ToWords());
// later, in a hosted service:
Humanizer.Configuration.Configurer.Formatters.Register("fr", myFormatter); // throws

// after: register during startup, before serving requests
Humanizer.Configuration.Configurer.Formatters.Register("fr", myFormatter);
var app = builder.Build();
app.MapGet("/x", () => 1.ToWords());
Defensive patterns

Strategy: validation

Validate before calling

// Ensure all Register calls happen before the first Humanizer resolve call.
// There is no public API to check the frozen state; enforce ordering structurally
// by registering only in your composition root, before serving any request.

Try / catch

try { Configurer.Formatters.Register("fr", myFormatter); }
catch (InvalidOperationException)
{ /* registry already in use: move registration earlier or use a private registry */ }

Prevention

When it happens

Trigger: Calling any Humanizer API that resolves a localiser (e.g. number.ToWords(), TimeSpan.Humanize()) and then later calling something like Configurer.Formatters.Register(...) or another LocaliserRegistry.Register. The first resolve freezes the internal dictionary, after which Register throws.

Common situations: App startup order bugs: a module registers a custom formatter in a delayed initializer or middleware that runs after the first request has already humanized something; testing code that registers per-test localisers but shares a static registry between tests; ASP.NET hosted services that resolve Humanizer during startup and then try to register in a later IHostedService.

Related errors


AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13). Data as JSON: /api/errors/33eca4da61d39a0b. Report an issue: GitHub.