tursodatabase/turso · error · std::io::Error
InvalidData
InvalidData
Error message
malformed chunk record
What it means
FTS index chunk records must carry (path: Text, chunk_no: Integer, bytes: Blob). While writing or rotating chunks, the code reads back the current record; if any column is missing or has the wrong type, it refuses with InvalidData "malformed chunk record" rather than corrupting the index further.
Source
Thrown at core/index_method/fts.rs:868
// Extract and validate
let found_path = record.get_value_opt(0).and_then(|v| match v {
crate::types::ValueRef::Text(t) => Some(t.value.to_string()),
_ => None,
});
let found_chunk = record.get_value_opt(1).and_then(|v| match v {
crate::types::ValueRef::Numeric(crate::numeric::Numeric::Integer(i)) => Some(i),
_ => None,
});
let bytes = record.get_value_opt(2).and_then(|v| match v {
crate::types::ValueRef::Blob(b) => Some(b.to_vec()),
_ => None,
});
let (found_path_str, found_chunk_no, bytes) = match (found_path, found_chunk, bytes) {
(Some(p), Some(c), Some(b)) => (p, c, b),
_ => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"malformed chunk record",
));
}
};
if found_path_str != path_str || found_chunk_no != expected_chunk_no as i64 {
return Err(io_not_found(format!(
"wrong chunk: expected {path_str}:{expected_chunk_no}, got {found_path_str}:{found_chunk_no}",
)));
}
// Cache and collect the chunk
if can_cache_chunks(path) {
let cache_key = (path.to_path_buf(), expected_chunk_no as i64);
self.chunk_cache.put(cache_key, bytes.clone());
}
chunks.push(Arc::from(bytes));View on GitHub (pinned to 244cde92a7)
Solutions
- Drop and rebuild the FTS index: `INSERT INTO ft(ft) VALUES('rebuild')` or DROP/CREATE the index
- If rebuilding fails, restore the database from a known-good backup
- Stop touching shadow tables directly - use the fts table's documented controls
- If it appeared right after a version change, report it with both turso versions
Example fix
-- before: index left malformed (e.g. after direct shadow-table edits)
-- after: rebuild the index from the content table
INSERT INTO ft(ft) VALUES('rebuild'); Defensive patterns
Strategy: fallback
Try / catch
match write_chunk_result {
Err(ref e) if e.kind() == std::io::ErrorKind::InvalidData => rebuild_fts_index(),
other => other,
} Prevention
- Never modify FTS shadow tables manually
- Rebuild indexes after restores and version upgrades
- Keep backups before bulk FTS writes
When it happens
Trigger: The FTS index storage no longer matches the expected record layout: shadow tables edited manually, a partially-written record after a crash, or an index built by an incompatible turso version.
Common situations: Direct INSERT/UPDATE into FTS shadow tables, a killed process leaving a half-written chunk, or downgrade/upgrade across format changes.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- UnexpectedEof
- Failed to read manual page: {}
- Manual page not found: {page_name}
- UnexpectedEof
- Unknown section
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/663c0b86f4de8c8b.
Report an issue: GitHub.