SQLite 3.51.3 fixes WAL reset after the 3.52.0 withdrawal
The WAL-reset corruption fix is available in SQLite 3.51.3. The withdrawal of 3.52.0 raises a separate compatibility question for expression indexes.
SQLite 3.51.3 is available today, 13 March 2026, with a fix for the WAL-reset database corruption bug. Its release follows the withdrawal of 3.52.0 because of compatibility problems involving certain expression indexes. The project announcement explains why a patch to the existing release series now supplies the corruption fix while the new features need more work. I would evaluate those two issues separately when deciding what to deploy.
I have used SQLite for twenty-five years, and this site runs on it. Its embedded model remains a good fit for the workloads I associate with it. A corruption fix still requires a deployment decision even when the triggering conditions are rare. The useful questions concern which connections access a file and which library versions can interpret the derived values already stored in it.
A maintenance release provides the immediate upgrade path
The 3.51.3 release log lists the WAL-reset repair and other minor fixes. This gives maintainers an upgrade target within the 3.51 series. The availability of that patch matters because adopting a new feature release and adopting a correctness repair need not be the same operational decision.
I would prefer to assess the patch against the application I already have. Adding unrelated schema or query changes during that assessment makes a failure harder to interpret. Keeping the application constant gives a comparison a clear purpose, even though it cannot establish that a rare race is absent through repeated successful runs.
There is also a distinction between installing a repaired library and repairing existing data. The release notes announce a code fix. I would not read them as a promise that replacing the library reconstructs transactions that an earlier failure may have damaged. Any suspicion about existing data deserves a separate investigation with a preserved copy and application-level checks.
WAL reuse depends on correct progress tracking
SQLite's WAL explanation describes the defect as a race involving multiple connections writing or checkpointing the same WAL-mode database. A completed checkpoint is followed by another checkpoint starting while a writer resets the log. Incorrect checkpoint progress then makes a later checkpoint skip content that should reach the main database. The documentation describes tight timing requirements and deliberate test instrumentation used to trigger them.
That mechanism explains why a successful commit is insufficient evidence for the later state of the main file. The error occurs in bookkeeping about which log content has already been copied. A test concerned only with a write returning successfully misses the subsequent checkpoint behavior. I would include reopen and application-state checks when testing the integration, while treating those checks as coverage of expected behavior rather than a probabilistic proof about this race.
The database format documentation supplies the underlying model. A WAL contains frames carrying database page content. Resetting the WAL allows reuse of its beginning after the old contents are no longer needed. The format uses salts to distinguish frames belonging to successive uses of the log. Correctly interpreting the file therefore requires more than looking at whether some bytes remain on disk.
For an operator, the distinction between allocated file length and valid database history is practical. I would avoid using the apparent size of a WAL file as evidence that a checkpoint has or has not completed. The file is an implementation artifact with reuse rules. Database APIs provide the relevant status, and the application provides the invariants that determine whether its own data is correct.
Checkpoint modes express waiting policy
The checkpoint API distinguishes PASSIVE, FULL, RESTART, and TRUNCATE modes. PASSIVE copies what it can without waiting for readers or writers. FULL waits under its documented conditions, and RESTART additionally waits until readers no longer need the WAL. TRUNCATE also reduces the log to zero bytes after successful completion. These modes expose different coordination requirements to the caller.
I would not change checkpoint mode casually in response to this announcement. Doing so changes waiting behavior and can complicate the comparison with the existing deployment. First establish the current mode and who invokes it. Then evaluate the repaired library with the existing settings, before considering a separate tuning change.
For example, an application with an explicit checkpoint worker deserves an inventory of that worker alongside its normal write connections. A review that counts only SQL request handlers leaves out a participant in the affected operation. The same applies to maintenance tools that open the file while the service remains active. Connection ownership should be documented in terms of actual processes and library calls.
Expression indexes create a separate compatibility obligation
The withdrawal concerns an interaction between 3.52.0 and earlier releases when certain indexed expressions produce floating-point values derived from text or JSONB. The announcement includes indexes on VIRTUAL computed columns in that description. It does not say that every database created or opened by 3.52.0 has become incompatible, so a blanket claim would misstate the scope.
SQLite's expression-index documentation explains why this class of issue exists. An index can store an expression over table columns, and the planner can use it when the query contains the matching expression. Such an index holds derived keys whose meaning depends on evaluating that expression. Compatibility therefore involves the relationship between stored keys and the values an engine computes when querying or updating them.
I find that distinction easy to overlook when discussing a stable file format. Being able to decode a record is one requirement. Agreeing about the expression that produced an indexed value is another. An upgrade assessment should include both, particularly when more than one executable opens the same database over its lifetime.
Generated columns need explicit attention in that inventory. The generated-column documentation distinguishes VIRTUAL values computed when read from STORED values computed when written. It also explains that indexing a VIRTUAL generated column creates an expression index. A schema review limited to visibly written expressions in CREATE INDEX statements can therefore overlook the same dependency expressed through a named column.
I would record which expressions use numeric conversions and which tools may access their indexes. That is a review question, not a diagnosis that every such expression triggers the withdrawn release's problem. Establishing the precise affected condition requires comparing the schema and value types with the announcement, including where the input originates.
Validate the database as well as the binary
SQLite provides integrity-check pragmas for examining internal database consistency. integrity_check checks matters such as index and table agreement, while foreign-key violations require a separate foreign_key_check. These checks answer different questions, and neither describes all business rules an application may impose on otherwise valid records.
On a controlled copy, the starting inspection can remain small. These statements inspect the schema and request the documented checks without adopting any 3.52-only SQL syntax.
SELECT type, name, sql
FROM sqlite_schema
WHERE type IN ('table', 'index')
ORDER BY type, name;
PRAGMA integrity_check;
PRAGMA foreign_key_check;
I would preserve the output with the exact runtime library identification used for the inspection. An integrity result without that context makes later comparisons ambiguous, especially if a service and its maintenance tools bundle different SQLite versions. Application-specific assertions should accompany it wherever there is a known expected relationship among records.
A controlled copy also needs a valid acquisition method. SQLite's online backup API produces a snapshot of the source database through its backup operations. I would use an established SQLite-aware backup procedure before making investigative changes. Copying whichever file happens to have the familiar database filename does not establish that the copy represents a consistent state of an active service.
I would also keep the baseline copy separate from the working copy used for investigation. Once an investigative tool writes to a database, later observations may describe the effects of that tool as well as the original application. Recording each operation makes a comparison reproducible and avoids relying on memory about which utility last opened the file.
For an application already on 3.51, today's patch offers a focused decision about the WAL repair. An application that has adopted 3.52.0 has an additional compatibility investigation to perform against its schema and access tools. I would keep the results of that investigation with the deployment record, including which executables can read or write the file and which version each actually loads.