Thanks, eventually not aware of the replies, made an inquiry and ended up with "manual" bisect by splitting sections at the timeline. The change that triggers the difference is [https://www.sqlite.org/cgi/src/info/2361b03b61311aab] (Remove another unnecessary local variable initialization from sqlite3VdbeExec()) The code fragment in question is (the difference between versions is the line with my comment "THIS IS THE LINE ...". I looked at the latest sqlite, basically these particular lines are the same, only isInterrupted wrapped in AtomicLoad) <code> assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );<br> assert( p->bIsReader || p->readOnly!=0 );<br> <b>p->rc = SQLITE_OK;</b> // THIS IS THE LINE THAT TRIGGERS THE CHANGE<br> p->iCurrentTime = 0;<br> assert( p->explain==0 );<br> p->pResultSet = 0;<br> db->busyHandler.nBusy = 0;<br> if( db->u1.isInterrupted ) goto abort_due_to_interrupt;<br> </code> I also noticed isInterrupted field here so I looked once more at my code and saw also an interrupt action so in order to clarify, the steps are * Thread1 (Main UI) asks the Thread2 Connection to sqlite3_interrupt, so the call is from Thread1, but for the connection of Thread2. This is because a new text is being entered so the previous query is no longer needed * Thread2 by reacting to an event triggered by the previous step starts a read-only query * Thread 1 begins deferred transaction, updates and calls Commit. If the line with <b>p->rc = SQLITE_OK</b> is omitted then sqlite3_step returns SQLITE_BUSY twice and returns SQLITE_DONE but failing to write. If the line is present then sqlite3_step allows calling it multiply times with SQLITE_BUSY result and correctly writes. I'm not the developer so this is only my speculation. According to the first assert the p->rc can have different values (not only SQLITE_OK), but if the interruption (last line) is triggered its final state might be different in two Sqlite versions so this change may be an optimization with unnoticed side effects.