{"record":{"id":"884dd2f2ef43b32e","repo":"astral-sh/ruff","slug":"expected-extension-languagecode-pattern","errorCode":null,"errorMessage":"Expected <Extension>:<LanguageCode> pattern","messagePattern":"Expected <Extension>:<LanguageCode> pattern","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ruff_linter/src/settings/types.rs","lineNumber":465,"sourceCode":"\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct ExtensionPair {\n    pub extension: String,\n    pub language: Language,\n}\n\nimpl ExtensionPair {\n    const EXPECTED_PATTERN: &'static str = \"<Extension>:<LanguageCode> pattern\";\n}\n\nimpl FromStr for ExtensionPair {\n    type Err = anyhow::Error;\n\n    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {\n        let (extension_str, language_str) = {\n            let tokens = s.split(':').collect::<Vec<_>>();\n            if tokens.len() != 2 {\n                bail!(\"Expected {}\", Self::EXPECTED_PATTERN);\n            }\n            (tokens[0].trim(), tokens[1].trim())\n        };\n        let extension = extension_str.into();\n        let language = Language::from_str(language_str)?;\n        Ok(Self {\n            extension,\n            language,\n        })\n    }\n}\n\nimpl From<ExtensionPair> for (String, Language) {\n    fn from(value: ExtensionPair) -> Self {\n        (value.extension, value.language)\n    }\n}\n","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/astral-sh/ruff/blob/d1087a4b9e03d253a88703f34e0869ee4b805456/crates/ruff_linter/src/settings/types.rs#L447-L483","documentation":"ExtensionPair::from_str parses each --extension value as '<Extension>:<LanguageCode>' by splitting on ':' and requiring exactly two tokens. A value with zero, one, or two-plus colons fails immediately, before the language string is even validated (a bad language yields error #22 instead).","triggerScenarios":"Passing --extension txt (missing language), --extension 'txt python' (wrong separator), or a value containing another colon such as an unescaped Windows path --extension 'C:\\tmp\\x.py:python'.","commonSituations":"Assuming --extension takes a bare file extension list; using '=' or space instead of ':'; shell quoting that swallows the colon.","solutions":["Rewrite as '<Extension>:<LanguageCode>', e.g. --extension 'txt:python'","Pass multiple mappings as separate flags or comma-separated values as documented by the flag","For permanent mappings, use the project.extension setting in pyproject.toml instead"],"exampleFix":"# before\nruff check --extension txt .\n# after\nruff check --extension 'txt:python' .","handlingStrategy":"validation","validationCode":"# bash: require exactly one colon in each --extension value\nval='txt:python'\nif [[ \"$(tr -cd ':' <<<\"$val\" | wc -c)\" -ne 1 ]]; then\n  echo \"need <Extension>:<LanguageCode>, e.g. 'txt:python'\" >&2; exit 1\nfi\nruff check --extension \"$val\" .","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Memorize the shape '<Extension>:<LanguageCode>' — bare extensions are rejected","Put long-lived mappings in the project.extension setting rather than CLI flags"],"tags":["cli","extension-mapping","argument-parsing","ruff-linter"],"backgroundTag":"invalid-cli-argument-format","analyzedSha":"d1087a4b9e03d253a88703f34e0869ee4b805456","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":"2026-08-20T16:33:49.445Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}