sqlite-net: SQLiteException: file is not a database

Steps to reproduce

We was not able to reproduce the problem explicitly.

Actual behaviour

We have a lot of crashes logged in appcenter about the problem “file is not a database” and others with different messages, but I suspect that all the problems could be related to the lock mechanism. Others sqlite related errors are:

  • SQLite.SQLiteException: Could not open database file:

  • SQLite.SQLiteException: Busy

  • System.InvalidOperationException: Cannot begin a transaction while already in a transaction

we don’t use async connection inside transactions, using a unique encrypted connection in the app, created with:

  • OpenFlags: SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex

Configuration

Operating system: Android, all versions from API 25 to API 29

Library Version: 1.7.335

.NET Version: NETStandard.Library 2.0.3

StackTrace

020-05-11 07:58:17.5910|Trace|BugReportingManager - CurrentDomain_UnhandledException - line: 149 | ****** Current Domain Unhandled Exception ****** 2020-05-11 07:58:17.5928|Error|BugReportingManager - PreparaCrashReport - line: 134 | SQLite.SQLiteException: file is not a database at SQLite.SQLite3.Prepare2 (SQLitePCL.sqlite3 db, System.String query) [0x00021] in C:\Jenkins\workspace\1.0.76\sqlite-net\src\SQLite.cs:4530 at SQLite.SQLiteCommand.Prepare () [0x00011] in C:\Jenkins\workspace\1.0.76\sqlite-net\src\SQLite.cs:3219 at SQLite.SQLiteCommand+<ExecuteDeferredQuery>d__121[T].MoveNext () [0x00079] in C:\Jenkins\workspace\1.0.76\sqlite-net\src\SQLite.cs:3115 at System.Collections.Generic.List1[T].AddEnumerable (System.Collections.Generic.IEnumerable1[T] enumerable) [0x00059] in /Users/builder/jenkins/workspace/archive-mono/2019-10/android/release/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:1108 at System.Collections.Generic.List1[T]…ctor (System.Collections.Generic.IEnumerable1[T] collection) [0x00062] in /Users/builder/jenkins/workspace/archive-mono/2019-10/android/release/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:87 at System.Linq.Enumerable.ToList[TSource] (System.Collections.Generic.IEnumerable1[T] source) [0x00018] in /Users/builder/jenkins/workspace/archive-mono/2019-10/android/release/external/corefx/src/System.Linq/src/System/Linq/ToCollection.cs:30 at SQLite.SQLiteCommand.ExecuteQuery[T] () [0x0001c] in C:\Jenkins\workspace\1.0.76\sqlite-net\src\SQLite.cs:3079 at SQLite.SQLiteConnection.Query[T] (System.String query, System.Object[] args) [0x00008] in C:\Jenkins\workspace\1.0.76\sqlite-net\src\SQLite.cs:1071

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Comments: 24 (8 by maintainers)

Most upvoted comments

Hello again! After some investigation I have good news and bad news.

Good News!

The bug is understood! The problem lies with opening Cipher v3 databases using the now packages v4 SQLCipher. Fortunately, there are workarounds that you can use today with 1.7 of this library.

You can do this using code by issue PRAGMAs to the connection string. There are two options:

1. Enter a compatibility mode

You can tell SQL to always use v3 compatibility:

var cstring = new SQLiteConnectionString (
				path,
				storeDateTimeAsTicks: true,
				key: key,
				postKeyAction: c => {
					c.Execute ("PRAGMA cipher_compatibility = 3");
				}
				);

2. One-time convert your database to v4

If you convert your database to v4 compatibility, then everything will just work. There is a [full guide on how to do this for cipher](Upgrading to SQLCipher 4).

var cstring = new SQLiteConnectionString (
				path,
				storeDateTimeAsTicks: true,
				key: key,
				postKeyAction: c => {
					c.ExecuteScalar<int> ("PRAGMA cipher_migrate");
				}
				);

The bad news…

I am not sure how to handle this automatically. I could take either of the two options (I prefer the compatibility mode one), but they both have downsides.

The downside of compat is that I will force even new databases to use v3 options and not benefit from new enhancements.

The downside of the conversion is that it is trick to do if people override the defaults and it comes with a performance penalty if I run the conversion every time you open the database.

Please comment!

I am not sure how to proceed. Do you want automatic handling of this? If so, which of this methods should be the default. Please comment again 😃

Same problem here. We have a encrypted DB and we use the sqlite-net-sqlcipher package.

Happens here as well in our app. We are using sqlite-net-sqlcipher.

Error:

Exception in async method.SQLite.SQLiteException: file is not a database at SQLite.SQLite3.Prepare2 (SQLitePCL.sqlite3 db, System.String query) [0x0001b] in <b7f631d5fc1944c0bd63336596c11967>:0 at SQLite.SQLiteCommand.Prepare () [0x00011] in <b7f631d5fc1944c0bd63336596c11967>:0

Repro steps:

  1. Install sqlite-net-sqlcipher 1.5.231
  2. Start app so that it creates its database file
  3. Upgrade to latest sqlite-net-sqlcipher 1.7.335
  4. Start app. Exception is triggered

Same problem on iOS under Xamarin development. Problem exists like: the sqlcipher db on app’s 1st run and installation, every thing is okay. Then when we run with second build/debug, file is not a database exception occurred. On the other platform, Android all is fine, so odd!

I believe that the SQLiteException: Row issue may be unrelated to the other problems. The SetKey methods in SQLite.cs should use ExecuteScalar<string> instead of Execute to handle the “ok” result set that is returned from PRAGMA key as of SQLCipher 4.3.0.