{"record":{"id":"ac38effd12606548","repo":"libnyanpasu/clash-nyanpasu","slug":"en-us-is-a-valid-bcp47-language-tag","errorCode":null,"errorMessage":"`en-US` is a valid BCP47 language tag","messagePattern":"`en-US` is a valid BCP47 language tag","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"info","filePath":"backend/nyanpasu-helper/src/locale.rs","lineNumber":29,"sourceCode":"}\n\n/// Parse and canonicalize a raw locale string, falling back to `en-US` when it\n/// is absent or not a valid BCP47 language tag.\n///\n// FIXME(sys-locale): `sys_locale::get_locale` documents that it returns a\n// BCP47 tag, but its Unix backend does not enforce this. It merely transforms\n// the `LANG` / `LC_*` environment variables (stripping `.<codeset>` / `@<mod>`\n// and turning `_` into `-`) without validating the grammar or filtering the\n// POSIX `C` / `POSIX` locales. On minimal Linux/CI environments where the\n// locale is `C` / `C.UTF-8`, it returns `Some(\"C\")` — a single-letter primary\n// subtag that is *not* a valid BCP47 language tag — instead of `None`. We must\n// therefore parse defensively here rather than trusting the documented\n// contract. Revisit if a future `sys-locale` release returns `None` for the\n// POSIX locale.\nfn locale_or_fallback(raw: Option<&str>) -> LanguageTag {\n    raw.and_then(|raw| LanguageTag::parse(raw).ok()?.canonicalize().ok())\n        .unwrap_or_else(|| {\n            LanguageTag::parse(\"en-US\").expect(\"`en-US` is a valid BCP47 language tag\")\n        })\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_get_system_locale() {\n        // Must never panic regardless of the host locale.\n        let locale = get_system_locale();\n        eprintln!(\"System locale: {}\", locale);\n    }\n\n    #[test]\n    fn invalid_or_absent_locale_falls_back_to_en_us() {\n        let fallback = LanguageTag::parse(\"en-US\").unwrap();\n        // The `C` locale (common in CI) has a single-letter primary subtag,","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/nyanpasu-helper/src/locale.rs#L11-L47","documentation":"locale_or_fallback converts a system locale string into a LanguageTag, defensively parsing and canonicalizing because sys-locale output isn't guaranteed valid. If parsing fails (or input is None), it falls back to a hardcoded \"en-US\" whose parse is asserted with .expect — the panic fires only if that constant stops parsing, i.e. a broken regex/parser or edited constant.","triggerScenarios":"Triggered only when LanguageTag::parse(\"en-US\") fails — practically impossible unless the language-tags crate is broken, the constant was edited to an invalid tag, or parsing is misconfigured (e.g. custom parser rejecting valid tags).","commonSituations":"Not hit in real deployments. Developers encounter it conceptually when changing the fallback constant or vendoring an incompatible version of the parsing crate.","solutions":["Do not modify the \"en-US\" fallback constant to a non-BCP47 value.","If you need a different default, verify it parses with LanguageTag::parse before committing.","Check for vendored/broken versions of the language-tags crate if this panics.","Add a unit test asserting the fallback parses, so a bad edit fails at test time instead of runtime."],"exampleFix":"// before: invalid fallback edit\nLanguageTag::parse(\"en_US\").expect(\"`en-US` is a valid BCP47 language tag\")\n\n// after: keep a valid BCP47 tag\nLanguageTag::parse(\"en-US\").expect(\"`en-US` is a valid BCP47 language tag\")","handlingStrategy":"validation","validationCode":"// Verify any custom fallback parses at startup\nfn valid_fallback(tag: &str) -> bool { LanguageTag::parse(tag).is_ok() }\nassert!(valid_fallback(\"en-US\"));","typeGuard":null,"tryCatchPattern":"catch_unwind around locale resolution; on panic, fall back to a raw string locale.","preventionTips":["Never edit the \"en-US\" fallback to a non-BCP47 value.","Add a unit test asserting the fallback parses.","Pin/verify the language-tags crate version.","Validate any new default locale with LanguageTag::parse first."],"tags":["panic","locale","i18n","fallback"],"backgroundTag":"internal-invariant-violation","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}