{"record":{"id":"0d6bdb283c72f065","repo":"oxc-project/oxc","slug":"unexpected-control-characters","errorCode":null,"errorMessage":"Unexpected control characters","messagePattern":"Unexpected control characters","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/eslint/no_control_regex.rs","lineNumber":33,"sourceCode":"        .iter()\n        .map(|ch| {\n            let label = match ch.kind {\n                CharacterKind::Octal1 | CharacterKind::Octal2 | CharacterKind::Octal3 => {\n                    format!(\n                        \"'{ch}' is a control character. It looks like a backreference, but there is no corresponding capture group.\"\n                    )\n                }\n                _ => {\n                    // Show the code point since the character itself is not printable\n                    let ch = format!(\"U+{:04X}\", ch.value);\n                    format!(\"'{ch}' is a control character.\")\n                }\n            };\n            ch.span.label(label)\n        })\n        .collect();\n\n    OxcDiagnostic::warn(if count > 1 {\n        \"Unexpected control characters\"\n    } else {\n        \"Unexpected control character\"\n    })\n    .with_help(\n        \"Avoid matching control characters in regular expressions. If intentional, disable this rule for the expression.\",\n    )\n    .with_labels(labels)\n}\n#[derive(Debug, Default, Clone)]\npub struct NoControlRegex;\n\ndeclare_oxc_lint!(\n    /// ### What it does\n    ///\n    /// Disallows control characters and some escape sequences that match\n    /// control characters in regular expressions.\n    ///","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/oxc-project/oxc/blob/36ec0ef2bae567d1a8413ada2fe795f1af1f2785/crates/oxc_linter/src/rules/eslint/no_control_regex.rs#L15-L51","documentation":"Diagnostic from the oxlint rule `no-control-regex`, plural branch (crates/oxc_linter/src/rules/eslint/no_control_regex.rs:33). When a regular expression contains MORE THAN ONE control character (ASCII 0x00–0x1F plus 0x7F), the message is plural: 'Unexpected control characters'. Each match gets its own label showing the character as `\\xNN`, `\\uNNNN`, or `U+XXXX` when unprintable. Control characters in regexes are usually invisible paste artifacts and very hard to review; the help suggests using Unicode escapes if intentional.","triggerScenarios":"A regex literal or RegExp string containing 2+ control characters, raw or escaped — e.g. `const re = /\\x00\\x1F/;` matching NUL and US, or a pasted pattern embedding raw 0x0B/0x03 bytes. `count > 1` in the diagnostic constructor selects this plural message.","commonSituations":"Copy-pasting protocols/terminal escape patterns from documentation or packet dumps; parsing binary or serial-port logs; ANSI escape matching (\\x1B sequences); files edited in editors that preserve invisible control bytes.","solutions":["If the control characters are accidental, retype the pattern so it contains only visible characters.","If intentional, rewrite each control character as an explicit escape the rule accepts and that is reviewable — e.g. use a Unicode escape sequence (help text suggestion) such as /\\u0000/ style, or match via `String.fromCharCode`-built patterns where appropriate.","For terminal/ANSI handling prefer a dedicated library (e.g. ansi-regex) rather than hand-written control patterns.","Suppress narrowly with `// oxlint-disable-next-line no-control-regex` on genuinely required control-character matching."],"exampleFix":"// before\nconst re = /[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]+/; // multiple control chars\n\n// after\nconst re = /[\\t\\r\\n]+/; // whitelist the whitespace controls you mean","handlingStrategy":"validation","validationCode":"// Gate: multiple control characters/escapes inside one regex literal\nconst controlRuns = src.match(/\\/[^\\/\\n]*\\\\x[01][0-9A-Fa-f][^\\/\\n]*\\\\x[01][0-9A-Fa-f][^\\/\\n]*\\//g) ||\n  (src.match(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g) || []).length > 1 ? true : false;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never paste regexes from terminals/packet dumps without re-typing control bytes.","Express intentional control matching with visible escapes and inline suppression.","Show invisibles in your editor when editing protocol-parsing regexes."],"tags":["lint","regex","control-characters","invisible-characters","oxlint"],"backgroundTag":"control-character-regex","analyzedSha":"36ec0ef2bae567d1a8413ada2fe795f1af1f2785","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}