0.16.20 breaking undocumented change to locales as en_US is not supported anymore

Issue Description

When I was running stalwart-cli apply on my config after deploying v0.16.20 I received the following error:

✗ update Search: Search: update failed for id singleton: error: invalidPatch |   Invalid value Str("nl_NL") for enum type NlNL. |   Properties: defaultLanguage
...
✗ reconcile Account: Account: update failed for id 0: error: invalidPatch |   Invalid value Str("nl_NL") for enum type NlNL. |   Properties: locale

Expected Behavior

Considering Locale | Stalwart and pre v0.16.20 support nl_NL I would expect this to still work.

Actual Behavior

Errors in apply

Reproduction Steps

  1. On Stalwart <0.16.20 apply via cli a local to en_US and observe it works
  2. On Stalwart >=0.16.20 apply via cli a local to en_US and observe it fails

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

PostgreSQL

Blob Storage

PostgreSQL

Search Engine

PostgreSQL

Directory Backend

Internal

Additional Context

Commit Use BCP-47 locales · stalwartlabs/stalwart@776bf7c · GitHub seems to introduce change to BCP-47 and there is some logic to allow support for _ AND - separators, but the settings/registry validation does not.

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

This matches what the source code shows. In current builds, Locale values are validated by the generic registry/JMAP patch handler (RegistryJsonEnumPatch), which calls EnumImpl::parse() directly on the submitted string with no separator normalization. The enum’s accepted spellings are hyphenated BCP‑47 style (e.g. en-US, nl-NL), matching the EnUS/NlNL variant names and confirmed by tests like assert_eq!(Locale::EnUS.as_str(), "en-US") in crates/scim/src/users/mod.rs.

The underscore-to-hyphen normalization (tag.replace('_', "-") plus BCP‑47 fallback resolution) only exists in the SCIM user-locale code path (resolve_tag/resolve_locale in crates/scim/src/users/mod.rs), not in the generic JMAP/registry patch path that stalwart-cli apply and Settings/Account updates go through. So submitting nl_NL (or en_US) via apply hits the raw enum parser and fails, while the same value would succeed through SCIM.

The /docs/ref/enum/locale.md reference page still lists all values in the underscore form (nl_NL, en_US, etc.), which is now out of sync with what the JMAP patch validator actually accepts (hyphenated). This does look like the undocumented breaking change you’re describing, and is worth a closer look from the team on whether the registry patch should normalize separators the same way SCIM does, or whether the docs/enum values should be republished in hyphenated form.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

Apologies, that was an oversight, this will be added to the changelog. To fix it you can change your plan to use the BCP-47 format. Stalwart v0.16.20 added new translations and improved the existing ones and part of that change required replacing the internationalisation library that Stalwart uses.