databendlabs/databend · error
Expected to have char
Error message
Expected to have char '{}', got '{:?}' at pos {} What it means
This is a parsing error thrown by `CursorReadBytesExt::must_ignore_byte` in databend-common-io. When a caller (e.g. `read_quoted_text` or `fast_read_quoted_text`) expects the next byte in the input cursor to be a specific character (such as an opening/closing quote), the helper consumes it if it matches; if the cursor's next byte differs, the parser aborts with the expected char, the actual peeked byte, and the cursor position.
Solutions
- Inspect the 'at pos N' value in the message and print the input around position N to see the actual byte encountered.
- Ensure the input begins and ends with a matching quote character before calling read_quoted_text.
- Normalize quote style (use ' or " consistently) and strip trailing whitespace/newlines from the input.
- If parsing user input, validate or pre-escape the literal before handing it to the cursor parser.
Example fix
// before: parser gets non-quote byte
let s = "abc".as_bytes().read_quoted_text(&mut buf)?;
// after: ensure the literal is quoted first
let input = "abc";
let s = format!("\"{}\"", input).as_bytes().read_quoted_text(&mut buf)?; Defensive patterns
Strategy: validation
Validate before calling
fn ensure_quoted(input: &[u8]) -> bool {
let q = input.first()?;
(*q == b'\'' || *q == b'"') && input.last() == Some(q) && input.len() >= 2
} Type guard
fn is_quoted_literal(s: &str) -> bool {
let b = s.as_bytes();
b.len() >= 2 && (b[0] == b'\'' || b[0] == b'"') && b[b.len()-1] == b[0]
} Try / catch
match input.as_bytes().read_quoted_text(&mut buf) {
Ok(s) => s,
Err(e) => { log::warn!("literal parse failed: {e}"); return default_literal(); }
} Prevention
- Always wrap values in a matching pair of quotes before parsing.
- Strip trailing whitespace/newlines from input before parsing.
- Log the cursor position from the error to pinpoint malformed input.
When it happens
Trigger: Calling `read_quoted_text`/`fast_read_quoted_text` on input where the byte at the current cursor position is not the expected delimiter — e.g. parsing an opening quote but the input has no quote at the start, a closing quote is missing or replaced by another character, or a malformed escape sequence shifted the cursor onto an unexpected byte.
Common situations: Parsing SQL-ish or serialized string values from user-supplied text (query literals, config files, CSV-like payloads) where quotes are unbalanced, single vs double quotes are mixed, or trailing whitespace/control characters sit where the parser expects a delimiter.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid temp table desc
- Expected to ignore a byte
- Expected to have bytes
- Expected to have insensitive bytes
- Must reach the buffer end
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/0efb44f522b7e888.
Report an issue: GitHub.
Appendix: source
Thrown at src/common/io/src/cursor_ext/cursor_read_bytes_ext.rs:145
self.ignore(|c| c == b)
}
fn ignore_bytes(&mut self, bs: &[u8]) -> bool {
let available = Cursor::split(self).1;
let len = bs.len();
if available.len() < len {
return false;
}
let eq = available[..len].iter().zip(bs).all(|(x, y)| x == y);
if eq {
BufRead::consume(self, len);
}
eq
}
fn must_ignore_byte(&mut self, b: u8) -> Result<()> {
if !self.ignore_byte(b) {
return Err(std::io::Error::new(
ErrorKind::InvalidData,
format!(
"Expected to have char '{}', got '{:?}' at pos {}",
b as char,
self.peek(),
self.position()
),
));
}
Ok(())
}
fn ignore_insensitive_bytes(&mut self, bs: &[u8]) -> bool {
let available = Cursor::split(self).1;
let len = bs.len();
if available.len() < len {
return false;
}View on GitHub (pinned to 288d84d76e)