oxc-project/oxc · warning
Unexpected control character
Error message
Unexpected control character
What it means
Diagnostic from the oxlint rule `no-control-regex`, singular branch (crates/oxc_linter/src/rules/eslint/no_control_regex.rs:33). When a regular expression contains EXACTLY ONE control character (ASCII 0x00–0x1F plus 0x7F), the message is 'Unexpected control character', with a label rendering that character as `\xNN`, `\uNNNN`, or `U+XXXX` if unprintable. Invisible control characters in patterns are a classic source of regexes that match nothing the author can see.
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
- Delete the stray control character if it is a paste artifact.
- If the match is intentional, replace it with an explicit, visible escape and suppress the rule on that line (`// oxlint-disable-next-line no-control-regex`).
- Anchor on the surrounding printable pattern instead of the control char when possible (e.g. match the delimiter token you can see).
- Sanitize inputs earlier (`str.replace(/[\x00-\x1F\x7F]/g, '')`) so regexes never need to match control characters.
Example fix
// before const end = /\x03/; // single control character (ETX) // after const end = /\u0003/; // explicit, plus inline suppression if required // oxlint-disable-next-line no-control-regex
Defensive patterns
Strategy: validation
Validate before calling
// Gate: any control character (raw or escaped) inside a regex literal const hasControlInRegex = /\/(?:[^\/\n\\]|\\.)*\\x[01][0-9A-Fa-f](?:[^\/\n\\]|\\.)*\//.test(src) || /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/.test(src);
Prevention
- Sanitize input early so patterns never need control-character matching.
- Use dedicated parsers/libraries for ANSI, CSV, and binary formats instead of hand-rolled regexes.
- Prefer \uNNNN-style escapes so intent is visible in review.
When it happens
Trigger: A regex literal or RegExp string containing exactly one control character — e.g. `/\x1F/` (unit separator), a raw pasted 0x7F DEL byte inside a character class, or `/\x00/` NUL matching. `count == 1` selects the singular message.
Common situations: Single escape left behind after cleaning a pasted pattern; matching a vendor log format that terminates lines with 0x03; CSV/EDI parsing with stray control separators; linting generated fixtures that embed one control byte.
Related errors
- Unexpected control characters
- Backreference '{back_reference}' will be ignored. It referen
- Backreference '{back_reference}' will be ignored. It referen
- Backreference '{back_reference}' will be ignored. It referen
- Unnecessary escape character {escape_char:?}
AI-assisted analysis of oxc-project/oxc@36ec0ef2ba (2026-08-20).
Data as JSON: /api/errors/b9f2cc4bbbe636de.
Report an issue: GitHub.