rust-lang/rust · critical
non-is_byte literal paired with NonAsciiCharInByte
Error message
non-is_byte literal paired with NonAsciiCharInByte
What it means
Internal invariant in escape-error reporting. `EscapeError::NonAsciiCharInByte` can only originate from byte-mode literals (`b'…'`, `b"…"`, `br"…"`), so the `match mode` arm handling it asserts the mode is one of `Byte`/`ByteStr`/`RawByteStr`. If the literal mode is `Str`, `Char`, or `RawStr`, the (mode, error) pair is inconsistent and the compiler panics — non-ASCII chars are legal in unicode string/char literals.
Source
Thrown at compiler/rustc_parse/src/lexer/unescape_error_reporting.rs:195
foreign_escape_suggestion(&mut diag, (&ec, span), err_span);
}
diag.emit()
}
EscapeError::TooShortHexEscape => dcx.emit_err(UnescapeError::TooShortHexEscape(err_span)),
EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
let (c, span) = last_char();
let is_hex = error == EscapeError::InvalidCharInHexEscape;
let ch = escaped_char(c);
dcx.emit_err(UnescapeError::InvalidCharInEscape { span, is_hex, ch })
}
EscapeError::NonAsciiCharInByte => {
let (c, span) = last_char();
let desc = match mode {
Mode::Byte => "byte literal",
Mode::ByteStr => "byte string literal",
Mode::RawByteStr => "raw byte string literal",
_ => panic!("non-is_byte literal paired with NonAsciiCharInByte"),
};
let mut err = dcx.struct_span_err(span, format!("non-ASCII character in {desc}"));
let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
format!(" but is {c:?}")
} else {
String::new()
};
err.span_label(span, format!("must be ASCII{postfix}"));
// Note: the \\xHH suggestions are not given for raw byte string
// literals, because they are araw and so cannot use any escapes.
if (c as u32) <= 0xFF && mode != Mode::RawByteStr {
err.span_suggestion_verbose(
span,
format!(
"if you meant to use the unicode code point for {c:?}, use a \\xHH escape"
),
format!("\\x{:X}", c as u32),
Applicability::MaybeIncorrect,View on GitHub (pinned to 22057b88b0)
Solutions
- Report as a rustc ICE with the source literal and backtrace
- Bisect toolchains to find the regressing commit
- As a temporary workaround, change the byte literal to a regular string literal if you can isolate the trigger
Defensive patterns
Strategy: validation
Validate before calling
fn literal_is_ascii_byte_candidate(lit: &str) -> bool {
// only single ASCII chars belong in b'...' / b"..." literals
lit.is_ascii() && (lit.len() == 1 || (lit.starts_with('\\') && lit.len() == 2))
}
// Only pair NonAsciiCharInByte diagnostic with literals where is_byte == true
if kind == NonAsciiCharInByte && !literal_is_ascii_byte_candidate(text) { return Ok(()); } Type guard
pub fn is_byte_literal_text(s: &str) -> bool {
s.is_ascii() && s.len() == 1
} Prevention
- When reporting NonAsciiCharInByte, ensure the literal under the span is a byte literal (b'...'/b"...") — never a char or string literal.
- Keep the 'is_byte' flag attached to the literal node when walking it, so you never mis-pair a non-byte literal with a byte-only diagnostic.
- Pre-filter non-ASCII characters in source: byte literals can only contain ASCII or byte escapes.
- Do not reuse a diagnostic enum value (NonAsciiCharInByte) across literal kinds; map per-kind.
When it happens
Trigger: The internal escape-error reporting path is invoked with `EscapeError::NonAsciiCharInByte` while passing a non-byte `Mode` (`Str`/`Char`/`RawStr`). Not reachable through well-formed user source.
Common situations: A compiler-internal regression after refactoring literal-mode handling; proc-macro or lint code that re-runs unescape with the wrong mode. Not something end users cause by writing Rust.
Related errors
- expected error
- no error found for supposedly invalid raw string literal
- layout decided on a larger discriminant type ({min_ity:?}) t
- encountered a non-arbitrary layout during enum layout
- obj_size_bound: unknown pointer bit size {bits}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/595d1ab25ad2f974.json.
Report an issue: GitHub.