oxc-project/oxc · warning

Unexpected control characters

Error message

Unexpected control characters

What it means

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.

Source

Thrown at crates/oxc_linter/src/rules/eslint/no_control_regex.rs:33

        .iter()
        .map(|ch| {
            let label = match ch.kind {
                CharacterKind::Octal1 | CharacterKind::Octal2 | CharacterKind::Octal3 => {
                    format!(
                        "'{ch}' is a control character. It looks like a backreference, but there is no corresponding capture group."
                    )
                }
                _ => {
                    // Show the code point since the character itself is not printable
                    let ch = format!("U+{:04X}", ch.value);
                    format!("'{ch}' is a control character.")
                }
            };
            ch.span.label(label)
        })
        .collect();

    OxcDiagnostic::warn(if count > 1 {
        "Unexpected control characters"
    } else {
        "Unexpected control character"
    })
    .with_help(
        "Avoid matching control characters in regular expressions. If intentional, disable this rule for the expression.",
    )
    .with_labels(labels)
}
#[derive(Debug, Default, Clone)]
pub struct NoControlRegex;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallows control characters and some escape sequences that match
    /// control characters in regular expressions.
    ///

View on GitHub (pinned to 36ec0ef2ba)

Solutions

  1. If the control characters are accidental, retype the pattern so it contains only visible characters.
  2. 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.
  3. For terminal/ANSI handling prefer a dedicated library (e.g. ansi-regex) rather than hand-written control patterns.
  4. Suppress narrowly with `// oxlint-disable-next-line no-control-regex` on genuinely required control-character matching.

Example fix

// before
const re = /[\x00-\x08\x0B\x0C\x0E-\x1F]+/; // multiple control chars

// after
const re = /[\t\r\n]+/; // whitelist the whitespace controls you mean
Defensive patterns

Strategy: validation

Validate before calling

// Gate: multiple control characters/escapes inside one regex literal
const controlRuns = src.match(/\/[^\/\n]*\\x[01][0-9A-Fa-f][^\/\n]*\\x[01][0-9A-Fa-f][^\/\n]*\//g) ||
  (src.match(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g) || []).length > 1 ? true : false;

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of oxc-project/oxc@36ec0ef2ba (2026-08-20). Data as JSON: /api/errors/0d6bdb283c72f065. Report an issue: GitHub.