This error occurs when SQLite detects corruption in a virtual table, most commonly in FTS (Full Text Search) tables. It indicates that the virtual table's internal data structures have been damaged or contain invalid data.
The SQLITE_CORRUPT_VTAB error is an extended error code for SQLITE_CORRUPT that is specifically used by virtual tables. Virtual tables in SQLite are interfaces to external data sources or special-purpose tables like FTS3, FTS4, and FTS5 (Full Text Search) tables. When you see this error, it means the virtual table implementation has detected that its internal content is corrupt or malformed. Virtual tables maintain their data in "shadow tables" - hidden tables that store the actual data and indexes. When these shadow tables become corrupted, inconsistent, or contain data that violates the virtual table's invariants, the virtual table module returns SQLITE_CORRUPT_VTAB to indicate the problem. This error is different from general database corruption because it's specific to the virtual table mechanism and its implementation. The main database file might be fine, but the specific virtual table's internal structures are damaged.
First, identify the specific virtual table causing the error by examining your query and error stack trace.
List all virtual tables in your database:
SELECT name, sql FROM sqlite_master
WHERE type = 'table' AND sql LIKE '%VIRTUAL%';If you're using FTS tables, they'll show up with CREATE VIRTUAL TABLE statements. Note the table name for the next steps.
For FTS tables (FTS3, FTS4, FTS5), try rebuilding the index which can often fix corruption:
For FTS3/FTS4:
INSERT INTO your_fts_table(your_fts_table) VALUES('rebuild');For FTS5:
INSERT INTO your_fts_table(your_fts_table, rank) VALUES('rebuild', 0);Replace your_fts_table with your actual table name. This forces the virtual table to rebuild its internal structures from the source data.
Check the integrity of the virtual table specifically:
For FTS tables:
INSERT INTO your_fts_table(your_fts_table) VALUES('integrity-check');This will report any issues found in the virtual table's internal structures. If it reports errors, the corruption is confirmed and you may need to recreate the table.
If rebuilding doesn't work, you'll need to recreate the virtual table:
1. First, back up the source data (the actual table that the FTS indexes):
CREATE TABLE your_table_backup AS SELECT * FROM your_table;2. Drop the corrupted virtual table:
DROP TABLE your_fts_table;3. Recreate the virtual table with the same schema:
CREATE VIRTUAL TABLE your_fts_table USING fts5(column1, column2);4. Repopulate it from the source table:
INSERT INTO your_fts_table SELECT column1, column2 FROM your_table;Review your code for improper transaction handling around virtual tables:
Bad pattern (can cause corruption):
// Triggering FTS update without proper parent table data
db.run("BEGIN TRANSACTION");
db.run("UPDATE fts_table SET content = ?", [newContent]); // FTS not ready
db.run("COMMIT");Good pattern:
db.run("BEGIN TRANSACTION");
try {
// Insert/update parent table first
db.run("INSERT INTO documents (id, text) VALUES (?, ?)", [id, text]);
// FTS table updates automatically via trigger or explicit insert
db.run("COMMIT");
} catch (error) {
db.run("ROLLBACK");
throw error;
}Ensure that if an INSERT or UPDATE that would trigger a virtual table update fails, the entire transaction is rolled back.
FTS3 vs FTS4 vs FTS5: If you're still using FTS3 or FTS4, consider migrating to FTS5. FTS5 has better error handling, improved performance, and is more resistant to corruption. It's also the actively maintained version.
Custom Virtual Tables: If you've implemented a custom virtual table module, ensure that your xUpdate, xBegin, and xCommit methods properly validate data before writing and correctly handle rollback scenarios. Virtual table implementations must maintain consistency of their shadow tables even when transactions are aborted.
WAL Mode Considerations: If your database is in WAL (Write-Ahead Logging) mode, ensure that checkpoint operations complete successfully. Incomplete checkpoints can leave virtual tables in an inconsistent state. You can manually checkpoint with PRAGMA wal_checkpoint(FULL);
Preventing Future Corruption:
- Always use transactions when modifying tables that have FTS virtual tables associated with them
- Ensure proper error handling in triggers that update virtual tables
- Don't manually modify the shadow tables (tables with names like your_fts_table_content, your_fts_table_segdir, etc.)
- Use PRAGMA integrity_check regularly to detect corruption early
Recovery Tools: For severe corruption where rebuilding doesn't work, SQLite provides a recovery API (available in SQLite 3.37.0+) that can extract data from corrupted databases. The .recover command in the sqlite3 shell can help salvage data from damaged virtual tables.
SQLITE_IOERR_WRITE: Disk I/O error during write
Disk I/O error during write operation
SQLITE_READONLY: Attempt to write a readonly database
How to fix "SQLITE_READONLY: Attempt to write a readonly database" in SQLite
SQLITE_CONSTRAINT_PRIMARYKEY: PRIMARY KEY constraint failed
How to fix "SQLITE_CONSTRAINT_PRIMARYKEY" in SQLite
SQLITE_READONLY_DBMOVED: Database file has been moved since opened
How to fix 'SQLITE_READONLY_DBMOVED: Database file has been moved since opened'
SQLITE_IOERR_SHORT_READ: Read returned less data than requested
How to fix 'SQLITE_IOERR_SHORT_READ: Read returned less data than requested' in SQLite