stalwartlabs/stalwart · error

{key}: {language} is missing the required "other" plural cat

Error message

{key}: {language} is missing the required "other" plural category

What it means

Every pluralized translation value must include the `other` category, which serves as the fallback form in the generated plural lookup. After checking for duplicates, the build script verifies the collected set contains `other`; if not it panics for that key/language. CLDR plural rules always require an `other` form, so a value without one cannot be compiled.

Source

Thrown at crates/common/build.rs:105

            .any(|value| split_plural_forms(value).is_some())
        {
            continue;
        }

        for (language, value) in translations {
            let Some(forms) = split_plural_forms(value) else {
                panic!(
                    "{key}: {language} has no plural categories while other languages do: {value:?}"
                );
            };
            let mut seen = HashSet::new();
            for (name, _) in &forms {
                if !seen.insert(*name) {
                    panic!("{key}: {language} repeats the plural category {name:?}");
                }
            }
            if !seen.contains("other") {
                panic!("{key}: {language} is missing the required \"other\" plural category");
            }
        }

        keys.insert(key.clone());
    }

    keys
}

fn plural_forms_literal(value: &str) -> String {
    let forms = split_plural_forms(value).expect("validated above");
    let other = forms
        .iter()
        .find(|(name, _)| *name == "other")
        .map(|(_, text)| *text)
        .expect("validated above");

    let mut literal = String::from("PluralForms {");

View on GitHub (pinned to e962003857)

Solutions

  1. Add an `other=<fallback text>` segment to the value for the named key/language in i18n.yml.
  2. If the fallback text is the same as another category's, duplicate that text under `other=`.
  3. Re-run the build to confirm the fix.

Example fix

# before
  pl: one={count} plik;few={count} pliki
# after
  pl: one={count} plik;few={count} pliki;other={count} plików
Defensive patterns

Strategy: validation

Validate before calling

let cats: HashSet<&str> = value.split(';').filter_map(|s| s.split_once('=').map(|(n, _)| n)).collect();
assert!(cats.contains("other"), "value must include an 'other' plural category");

Prevention

When it happens

Trigger: A language's value for a pluralized key lists categories like `one=...;few=...` but omits `other=...` in `resources/locales/i18n.yml`.

Common situations: Translators add only the categories they consider natural for their language (e.g. one/few for Slavic languages) and skip the fallback; partial edits truncate the value after the last `;`.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06). Data as JSON: /api/errors/16e9b11fb916b99d. Report an issue: GitHub.