BurntSushi/ripgrep · error · Error

the literal {:?} is not allowed in a regex

Error message

the literal {:?} is not allowed in a regex

What it means

strip_from_match removes the line-terminator byte from character classes where possible, but if a regex *must* match the line terminator as a literal (a bare literal, or a singleton/fully-stripped class), there is no safe rewrite and ErrorKind::NotAllowed(lit) is returned. The Display tells the user that literal is not allowed and (at the CLI layer) suggests enabling multiline mode (-U) so newlines can be matched.

Source

Thrown at crates/regex/src/strip.rs:60

) -> Result<Hir, Error> {
    if line_term.is_crlf() {
        let expr1 = strip_from_match_ascii(expr, b'\r')?;
        strip_from_match_ascii(expr1, b'\n')
    } else {
        strip_from_match_ascii(expr, line_term.as_byte())
    }
}

/// The implementation of strip_from_match. The given byte must be ASCII.
/// This function returns an error otherwise. It also returns an error if
/// it couldn't remove `\n` from the given regex without leaving an empty
/// character class in its place.
fn strip_from_match_ascii(expr: Hir, byte: u8) -> Result<Hir, Error> {
    if !byte.is_ascii() {
        return Err(Error::new(ErrorKind::InvalidLineTerminator(byte)));
    }
    let ch = char::from(byte);
    let invalid = || Err(Error::new(ErrorKind::NotAllowed(ch.to_string())));
    Ok(match expr.into_kind() {
        HirKind::Empty => Hir::empty(),
        HirKind::Literal(hir::Literal(lit)) => {
            if lit.iter().find(|&&b| b == byte).is_some() {
                return invalid();
            }
            Hir::literal(lit)
        }
        HirKind::Class(hir::Class::Unicode(mut cls)) => {
            if cls.ranges().is_empty() {
                return Ok(Hir::class(hir::Class::Unicode(cls)));
            }
            let remove = hir::ClassUnicode::new(Some(
                hir::ClassUnicodeRange::new(ch, ch),
            ));
            cls.difference(&remove);
            if cls.ranges().is_empty() {
                return invalid();

View on GitHub (pinned to 3fce3b5bb0)

Solutions

  1. Enable multiline mode: use the -U/--multiline flag (or (?m) / (?s) in the pattern) so the line terminator can be matched.
  2. Remove the line-terminator literal from the pattern if you did not intend a multi-line match.
  3. Change the configured line terminator to a byte not used in your pattern.

Example fix

// before
// $ rg 'foo\nbar'   -> the literal '\n' is not allowed in a regex

// after
// $ rg -U 'foo\nbar' // multiline mode allows matching newlines
Defensive patterns

Strategy: validation

Validate before calling

fn needs_multiline(pat: &str, lt: u8) -> bool {
    pat.contains(lt as char) || pat.contains(&format!("\\x{:02X}", lt))
}

Try / catch

if let Err(e) = build_regex(pat, line_term) {
    eprintln!("{e} -- try enabling multiline mode (-U)");
}

Prevention

When it happens

Trigger: Building a non-multiline regex whose pattern contains the line terminator as a literal — e.g. searching with default line terminator \n and a pattern like 'foo\nbar', '\n', '\x0A', or a class that reduces to only \n after stripping (e.g. [\n]).

Common situations: rg 'foo\nbar' without -U; a pattern intended to span lines written without enabling multiline mode; a generated pattern that embeds the record separator.

Related errors


AI-assisted analysis of BurntSushi/ripgrep@3fce3b5bb0 (2026-08-06). Data as JSON: /data/errors/24159c136cfc8164.json. Report an issue: GitHub.