rust-lang/rust · critical

no error found for supposedly invalid raw string literal

Error message

no error found for supposedly invalid raw string literal

What it means

Internal compiler error in `report_raw_str_error`. This function is only entered once the lexer has already decided a raw string literal is malformed, so `rustc_lexer::validate_raw_str` is contractually expected to return an `Err` describing the problem. If validation instead returns `Ok(())`, the lexer's high-level parsing and the validator disagree, and the compiler panics instead of emitting a potentially incorrect diagnostic.

Source

Thrown at compiler/rustc_parse/src/lexer/mod.rs:951

        &self.src[self.src_index(start)..self.src_index(end)]
    }

    /// Slice of the source text spanning from `start` until the end
    fn str_from_to_end(&self, start: BytePos) -> &'src str {
        &self.src[self.src_index(start)..]
    }

    fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
        match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
            Err(RawStrError::InvalidStarter { bad_char }) => {
                self.report_non_started_raw_string(start, bad_char)
            }
            Err(RawStrError::NoTerminator { expected, found, possible_terminator_offset }) => self
                .report_unterminated_raw_string(start, expected, possible_terminator_offset, found),
            Err(RawStrError::TooManyDelimiters { found }) => {
                self.report_too_many_hashes(start, found)
            }
            Ok(()) => panic!("no error found for supposedly invalid raw string literal"),
        }
    }

    fn report_non_started_raw_string(&self, start: BytePos, bad_char: char) -> ! {
        self.dcx()
            .struct_span_fatal(
                self.mk_sp(start, self.pos),
                format!(
                    "found invalid character; only `#` is allowed in raw string delimitation: {}",
                    escaped_char(bad_char)
                ),
            )
            .emit()
    }

    fn report_unterminated_raw_string(
        &self,
        start: BytePos,

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Capture the exact raw-string literal that triggers the panic into a minimal standalone file
  2. Report it as a rust-lang/rust ICE with the literal and `RUST_BACKTRACE=1` output
  3. Bisect nightly toolchains to find the introducing commit if it is a recent regression
  4. Rewrite the offending literal as a normal `"..."` string or with a different hash count as a temporary workaround
Defensive patterns

Strategy: validation

Validate before calling

fn raw_string_is_well_formed(src: &str) -> bool {
    // r#...# with matching hash counts and a closing delimiter
    let bytes = src.as_bytes();
    if bytes.len() < 2 || bytes[0] != b'r' { return false; }
    let mut i = 1; let mut hashes = 0;
    while i < bytes.len() && bytes[i] == b'#' { hashes += 1; i += 1; }
    if i >= bytes.len() || bytes[i] != b'"' { return false; }
    let closer = format!('"' + &"#".repeat(hashes));
    src[i+1..].ends_with(&closer)
}
if !raw_string_is_well_formed(literal_src) { return Ok(()); }

Try / catch

use std::panic;
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
    lexer.report_invalid_raw_string(span)
}));

Prevention

When it happens

Trigger: Lexing a raw string literal (`r"..."`, `br"..."`, `r#"..."#`) whose delimiter/hash-count state the lexer flagged as invalid, but which `validate_raw_str` then classifies as well-formed.

Common situations: Edge cases in hash-delimiter counting or partially-terminated raw strings, typically surfaced by fuzzing, machine-generated source, or a regression after lexer refactors.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/376bd288243e3007.json. Report an issue: GitHub.