This error occurs when SQLite cannot access or open a database file. Common causes include incorrect file permissions, missing directories, invalid file paths, or insufficient disk space.
The SQLITE_CANTOPEN error (error code 14) indicates that SQLite was unable to open a file required for database operations. This file could be the primary database file itself, or one of several temporary disk files that SQLite creates for operations like journaling, write-ahead logging (WAL), or temporary storage. When SQLite attempts to open a database, it needs both read and write access to the database file and its containing directory. The directory access is crucial because SQLite creates auxiliary files like journal files and WAL files in the same location. If any of these access requirements aren't met, SQLite fails with the CANTOPEN error. This error is particularly common in containerized environments, cross-platform deployments, or when applications are moved between different file system configurations without updating permissions or paths.
First, confirm that the path to your database file is accurate and that the file exists.
# Check if the database file exists
ls -l /path/to/your/database.db
# If using a relative path, check your current working directory
pwdIf you're using a relative path like ./database.db, make sure your application's working directory is what you expect. Consider using an absolute path to avoid confusion:
// Instead of:
const db = new Database('./data.db');
// Use absolute path:
const db = new Database('/var/app/data/data.db');Ensure the user running your application has read and write permissions on both the database file and its parent directory.
# Check current permissions
ls -la /path/to/database.db
ls -ld /path/to/
# Grant read/write permissions to the user
chmod 664 /path/to/database.db
chmod 775 /path/to/
# If needed, change ownership to your application user
chown appuser:appgroup /path/to/database.db
chown appuser:appgroup /path/to/The directory needs write permission because SQLite creates journal files and other temporary files in the same location as the database.
If the database file or its parent directory doesn't exist, create them before opening the database.
# Create directory structure with proper permissions
mkdir -p /path/to/database/
chmod 775 /path/to/database/In your application code, you can also create the directory programmatically:
const fs = require('fs');
const path = require('path');
const dbPath = '/var/app/data/database.db';
const dbDir = path.dirname(dbPath);
// Create directory if it doesn't exist
if (!fs.existsSync(dbDir)) {
fs.mkdirSync(dbDir, { recursive: true, mode: 0o775 });
}Check that your disk has enough free space for database operations.
# Check available disk space
df -h /path/to/database/
# Check disk usage of the directory
du -sh /path/to/database/SQLite needs space not just for the database file, but also for temporary files during operations. Aim to keep at least 10-20% of your disk free.
If disk space is limited, you can configure SQLite to use in-memory temporary storage:
PRAGMA temp_store = MEMORY;Verify that the TEMP environment variable points to an existing, writable directory.
# Check current TEMP directory
echo $TMPDIR # On Linux/Mac
echo $TEMP # On Windows
# Create the directory if missing
mkdir -p /tmp/sqlite-temp
export TMPDIR=/tmp/sqlite-tempYou can also configure SQLite to use a specific temporary directory in your code:
const Database = require('better-sqlite3');
const db = new Database('mydb.db');
// Set temporary directory
db.pragma('temp_store_directory = "/tmp/sqlite-temp"');Or use in-memory temporary storage to avoid file system issues entirely:
PRAGMA temp_store = MEMORY;If you're using WAL (Write-Ahead Logging) mode and experiencing CANTOPEN errors on read-only connections, ensure the WAL file exists or switch to rollback journal mode.
-- Check current journal mode
PRAGMA journal_mode;
-- Switch to WAL mode (requires write access)
PRAGMA journal_mode = WAL;
-- Or switch back to rollback journal
PRAGMA journal_mode = DELETE;For read-only connections to WAL databases, the -wal file must exist. If you're opening a read-only copy of a database, ensure you copy all associated files:
# Copy all database files including WAL and SHM
cp database.db database.db-wal database.db-shm /destination/In Docker or other containerized environments, ensure proper volume mounts and permissions.
# docker-compose.yml
services:
app:
image: myapp
volumes:
# Mount with proper permissions
- ./data:/var/app/data
user: "1000:1000" # Match host user ID
environment:
- DATABASE_PATH=/var/app/data/database.dbIf using a named volume, ensure it's properly initialized:
# Create volume with correct permissions
docker volume create app-data
# Or fix permissions in container startup
docker exec -it mycontainer chown -R appuser:appgroup /var/app/dataSELinux and AppArmor Considerations:
On systems with SELinux or AppArmor enabled, security policies may block SQLite from accessing files even with correct Unix permissions. Check audit logs and add appropriate policies:
# Check SELinux denials
sudo ausearch -m avc -ts recent
# Temporarily set to permissive for testing
sudo setenforce 0
# Or add specific policy for your app
sudo setsebool -P httpd_unified 1Extended Error Codes:
SQLite provides extended error codes that give more specific information. The SQLITE_CANTOPEN_ISDIR extended code (error 526) indicates you're trying to open a directory instead of a file. Enable extended error codes in your SQLite driver to get more detailed diagnostics.
Database File Location Best Practices:
- Avoid storing databases in system directories (/tmp, /var/tmp) as they may be cleared on reboot
- Use application-specific directories like /var/lib/myapp or ~/.local/share/myapp
- In production, consider using a dedicated data volume or partition
- Always use absolute paths in configuration files to avoid working directory issues
Performance Impact:
While using PRAGMA temp_store = MEMORY solves permission issues, it increases memory usage. For large operations (sorting, indexing), this can lead to out-of-memory errors. Monitor memory usage if you enable this setting.
File Locking:
On network file systems (NFS, SMB), file locking may not work correctly, leading to database corruption or CANTOPEN errors. SQLite is designed for local file systems and may have issues on network shares. Consider using a client-server database for network scenarios.
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'