{"record":{"id":"547c4b551fb0161f","repo":"astral-sh/ruff","slug":"expected-filepattern-rulecode-pattern","errorCode":null,"errorMessage":"Expected <FilePattern>:<RuleCode> pattern","messagePattern":"Expected <FilePattern>:<RuleCode> pattern","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ruff_linter/src/settings/types.rs","lineNumber":386,"sourceCode":"\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct PatternPrefixPair {\n    pub pattern: String,\n    pub prefix: UnresolvedRuleSelector,\n}\n\nimpl PatternPrefixPair {\n    const EXPECTED_PATTERN: &'static str = \"<FilePattern>:<RuleCode> pattern\";\n}\n\nimpl FromStr for PatternPrefixPair {\n    type Err = anyhow::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let (pattern_str, code_string) = {\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 pattern = pattern_str.into();\n        let prefix = UnresolvedRuleSelector::cli(code_string);\n        Ok(Self { pattern, prefix })\n    }\n}\n\n#[derive(\n    Clone,\n    Copy,\n    Debug,\n    PartialOrd,\n    Ord,\n    PartialEq,\n    Eq,\n    Default,","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/astral-sh/ruff/blob/d1087a4b9e03d253a88703f34e0869ee4b805456/crates/ruff_linter/src/settings/types.rs#L368-L404","documentation":"Ruff parses CLI values for --per-file-ignores / --extend-per-file-ignores as PatternPrefixPair, which requires exactly one colon separating a file glob from a rule selector. The string given did not split into exactly two ':'-delimited tokens, so Ruff rejects it before reading any configuration. This is purely a command-line argument format error.","triggerScenarios":"Passing a rule code without a file pattern (`--per-file-ignores E501`), passing only a pattern (`--per-file-ignores 'src/*'`), or using extra colons (`--per-file-ignores 'a.py:E5:01'`, or an unescaped Windows drive path like `C:\\x.py:E501` which yields three tokens).","commonSituations":"Copy-pasting a pyproject.toml per-file-ignores value (which is a table, not a string) onto the CLI; assuming --per-file-ignores takes only a rule code; quoting mistakes in shell scripts.","solutions":["Rewrite the value as '<FilePattern>:<RuleCode>', e.g. --per-file-ignores 'src/legacy/*.py:E501'","Use a comma to pass multiple pairs: --per-file-ignores 'a.py:E501,b.py:F401'","Prefer the pyproject.toml [tool.ruff.lint.per-file-ignores] table for anything non-trivial"],"exampleFix":"# before\nruff check --per-file-ignores E501 .\n# after\nruff check --per-file-ignores 'src/legacy/*.py:E501' .","handlingStrategy":"validation","validationCode":"# bash: require exactly one colon before passing the flag\npair='src/legacy/*.py:E501'\nif [[ \"$(tr -cd ':' <<<\"$pair\" | wc -c)\" -ne 1 ]]; then\n  echo \"need <FilePattern>:<RuleCode>, e.g. 'src/*.py:E501'\" >&2; exit 1\nfi\nruff check --per-file-ignores \"$pair\" .","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember the CLI form is one '<glob>:<RuleCode>' string per pair, comma-separated for multiple","Keep complex per-file rules in the pyproject [tool.ruff.lint.per-file-ignores] table instead of CLI flags","Escape Windows drive-path colons or use forward-slash relative globs"],"tags":["cli","per-file-ignores","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"}