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

  1. Drop and rebuild the FTS index: `INSERT INTO ft(ft) VALUES('rebuild')` or DROP/CREATE the index
  2. If rebuilding fails, restore the database from a known-good backup
  3. Stop touching shadow tables directly - use the fts table's documented controls
  4. 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

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

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/663c0b86f4de8c8b. Report an issue: GitHub.