SQLite unable to open database file: causes and fixes
Solved Email & Outlook
MS
Michael Scofield
October 13, 2020
2 replies
11,240 views
Reviewed by moderators

Deployed our application to the server and every database call fails with unable to open database file, though the same code and database run perfectly on my development machine.

The file exists at the path and looks readable. What does this error actually cover?

Accepted Answer
Verified by Eddie Thwan, Forum Moderator ยท Reviewed October 2020

It covers more than its words admit, which is why the file looking fine proves little. Works locally, fails deployed narrows it to the environment and these are the environment's usual confessions in order:

Relative path resolution, the classic: a connection string like data/app.db resolves against the process's working directory, which on your machine is the project folder and on the server is wherever the service manager started the process, frequently the system directory. The file exists at the path you think of while the process looks somewhere else entirely. The fix is an absolute path in deployed configuration, or resolving the path in code against the application's own directory before handing it to SQLite, and logging the resolved absolute path at startup so the next mystery answers itself.

Directory writability, the equal classic: the service account, an app pool identity or systemd service user rather than your interactive login, needs write on the directory for the journal and WAL companions as covered deeper in the SQLITE_READONLY thread linked alongside and unable to open is how a fresh connection often reports that denial. Test as the actual account, sudo -u serviceuser touch in the directory or the Windows equivalent, not as yourself.

The deployment residue pair completes most cases: leftover -wal and -shm files copied from the development machine alongside the database confuse the opening handshake when their ownership or state mismatches, delete the companions on the server and let a clean open recreate them, the database file itself carries everything committed. And containers or restrictive service configurations, ReadOnlyPaths in a systemd unit, a read only container filesystem layer, an antivirus jail on the directory, each produce this exact error with everything else looking correct, checked respectively in the unit file, the container spec and the AV logs.

The five minute diagnostic that sorts all of it: log the resolved path, then from a shell as the service account, attempt to create a file in that directory and open the database with the sqlite3 command line tool. Those two attempts fail in the same way the application does and their error messages speak plain OS language rather than SQLite's summary.

Relative path, resolved against the systemd working directory which was the root filesystem. Absolute path in the deployed config and startup logging added, working in minutes. The shell as service account diagnostic found it before I finished reading the rest of the answer.