SQLITE_CANTOPEN occurs when SQLite cannot access the database file due to missing files, incorrect paths, or permission issues. This guide covers checking file permissions, using absolute paths, and ensuring directory access.
The SQLITE_CANTOPEN error code (error code 14) indicates that SQLite was unable to open a file. This error is returned primarily in the OS abstraction layer, meaning something with file or directory access is preventing SQLite from reading or creating the database file. In node-sqlite3, this error typically manifests when the library attempts to open a database connection but encounters filesystem-level issues. The error can occur with primary database files, temporary disk files, or journal files that SQLite uses for transaction management. Common scenarios include missing database files when using SQLITE_OPEN_READWRITE mode, incorrect file paths (especially relative paths in production environments), permission restrictions, or issues with the parent directory not being writable.
First, check if the database file actually exists and the path is correct:
const sqlite3 = require('sqlite3').verbose();
const fs = require('fs');
const path = require('path');
const dbPath = './database.db';
// Check if file exists
if (!fs.existsSync(dbPath)) {
console.log('Database file does not exist at:', path.resolve(dbPath));
} else {
console.log('Database file found at:', path.resolve(dbPath));
}If the file doesn't exist and you want SQLite to create it, ensure you're using the correct open flags or create it first.
Relative paths can break when the working directory changes (common in production, Docker, or when run from cron):
const path = require('path');
// Bad: Relative path
const db = new sqlite3.Database('./database.db');
// Good: Absolute path
const dbPath = path.join(__dirname, 'database.db');
const db = new sqlite3.Database(dbPath);
// Or for project root
const dbPath = path.join(process.cwd(), 'data', 'database.db');This ensures the database is always accessed from the correct location regardless of where the script is executed from.
Verify that the user running the Node.js process has read and write permissions:
# Check file permissions
ls -la database.db
# Fix permissions (give owner read/write)
chmod 644 database.db
# Fix ownership if needed
sudo chown $USER:$USER database.db
# Check parent directory permissions (must be writable)
ls -la $(dirname database.db)
chmod 755 /path/to/database/directoryThe directory containing the database must also be writable because SQLite creates temporary files (journal, WAL) in the same directory.
Make sure the parent directory exists and use appropriate flags when opening the database:
const sqlite3 = require('sqlite3').verbose();
const fs = require('fs');
const path = require('path');
const dbPath = path.join(__dirname, 'data', 'database.db');
const dbDir = path.dirname(dbPath);
// Create directory if it doesn't exist
if (!fs.existsSync(dbDir)) {
fs.mkdirSync(dbDir, { recursive: true });
}
// Open database with create flag
const db = new sqlite3.Database(dbPath, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
if (err) {
console.error('Error opening database:', err.message);
} else {
console.log('Connected to database successfully');
}
});The OPEN_CREATE flag allows SQLite to create the database file if it doesn't exist.
Check if another process has the database locked:
# On Linux, check what process has the file open
lsof database.db
# Or using fuser
fuser database.dbIf another process is using the database, either close that process or implement proper connection pooling. Also check if antivirus software is scanning the database file and temporarily blocking access.
Extended Error Codes: SQLite provides extended result codes for SQLITE_CANTOPEN including SQLITE_CANTOPEN_ISDIR (when the file is actually a directory) and SQLITE_CANTOPEN_FULLPATH (when the OS cannot convert the filename to a full pathname). Enable these with sqlite3.verbose() for more specific diagnostics.
Docker and Container Environments: In containerized environments, ensure volume mounts are configured correctly and the container user has appropriate permissions. Consider using named volumes instead of bind mounts to avoid permission issues.
Temporary Files Configuration: If directory permissions cannot be changed, configure SQLite to use an alternative location for temporary files by setting the PRAGMA temp_store_directory, or use :memory: mode for testing scenarios where persistence isn't required.
SELinux and AppArmor: On systems with SELinux or AppArmor, security policies might prevent database access even when file permissions appear correct. Check audit logs and adjust security contexts if necessary.
SQLITE_CORRUPT_VTAB: Content in virtual table is corrupt
Content in virtual table is corrupt
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'