databendlabs/databend · error
Expected to have terminated string literal after quota
Error message
Expected to have terminated string literal after quota {:?}, while consumed buf: {:?} What it means
Thrown by `CursorReadStringExt::read_quoted_text` when the closing quote for a string literal is never found. The parser consumes bytes into `buf` until EOF (or a non-continuation branch breaks the loop) and then reports the expected quote character plus everything it consumed, so the developer can see how far parsing got.
Solutions
- Check the consumed buffer in the message — the missing closing quote is at the end of that content.
- Ensure the literal is wrapped in a matching pair of the same quote character.
- Fix the upstream producer/serializer so it always emits balanced quotes.
- Validate literal balance with a quick count of unescaped quote chars before parsing.
Example fix
// before let input = "'unterminated value"; // after let input = "'unterminated value'";
Defensive patterns
Strategy: validation
Validate before calling
fn balanced_quotes(input: &str, quote: char) -> bool {
let mut escaped = false;
let mut count = 0;
for c in input.chars() {
if escaped { escaped = false; continue; }
match c { '\\' => escaped = true, _ if c == quote => count += 1, _ => {} }
}
count % 2 == 0
} Type guard
fn is_closed_literal(s: &str) -> bool {
let b = s.as_bytes();
b.len() >= 2 && b[b.len()-1] == b[0] && (b[0] == b'\'' || b[0] == b'"')
} Try / catch
match read_quoted_text(&mut buf) {
Ok(s) => s,
Err(e) => {
// message includes the consumed buffer; surface it for diagnostics
return Err(anyhow!("unterminated literal: {e}"));
}
} Prevention
- Validate quote balance before parsing user-supplied literals.
- Escape quote characters inside literal content.
- Fix upstream serializers to always close quoted values.
When it happens
Trigger: Calling `read_quoted_text` with a quote character (e.g. `'`) on input that opens the quote but never closes it: the entire remaining buffer is consumed and the error names the quote char and consumed buffer.
Common situations: Malformed SQL/text literals pasted from editors that stripped the closing quote, multi-line strings split across lines, or serialization bugs that emit one quote instead of two.
Related errors
- Expected to have terminated string literal after quota '…
- Expected to have char
- Expected to have quotes in string literal.
- Expected to have terminated string literal after escaped…
- {e}
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/546abc5c170ef710.
Report an issue: GitHub.
Appendix: source
Thrown at src/common/io/src/cursor_ext/cursor_read_string_ext.rs:79
match c {
b'n' => buf.push(b'\n'),
b't' => buf.push(b'\t'),
b'r' => buf.push(b'\r'),
b'0' => buf.push(b'\0'),
b'\'' => buf.push(b'\''),
b'\"' => buf.push(b'\"'),
b'\\' => buf.push(b'\\'),
b'/' => buf.push(b'/'),
_ => {
buf.push(b'\\');
buf.push(c);
}
}
} else {
break;
}
}
Err(std::io::Error::new(
ErrorKind::InvalidData,
format!(
"Expected to have terminated string literal after quota {:?}, while consumed buf: {:?}",
quote as char, buf
),
))
}
fn read_escaped_string_text(&mut self, buf: &mut Vec<u8>) -> Result<()> {
loop {
self.keep_read(buf, |f| f != b'\\');
if self.ignore_byte(b'\\') {
let buffer = Cursor::split(self).1;
let c = buffer[0];
match c {
b'\'' | b'\"' | b'\\' | b'/' | b'`' => {
buf.push(c);
self.consume(1);View on GitHub (pinned to 288d84d76e)