This error occurs when Sequelize cannot open the SQLite database file at the specified path. Common causes include missing database file, incorrect file path, missing parent directory, or insufficient file/directory permissions. The error prevents Sequelize from establishing a connection to your SQLite database.
The SQLITE_CANTOPEN error indicates that SQLite's underlying file system layer cannot open the database file. When using Sequelize with SQLite, this error is wrapped in a "ConnectionError" and prevents your application from connecting to the database. This typically happens when: - The database file does not exist at the specified path - The parent directory does not exist - The application lacks read or write permissions to the database file or directory - The file path is incorrectly specified (relative vs absolute paths, Windows drive letter issues) - The database is locked or in use by another process - The directory where the database should be created lacks write permissions Unlike other databases (PostgreSQL, MySQL), SQLite is file-based, so any filesystem-level issue directly prevents connection.
Relative paths can be confusing in Node.js. Always use absolute paths with Sequelize SQLite. Update your connection configuration:
const path = require('path');
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: path.join(__dirname, 'database.sqlite') // Absolute path
// NOT: storage: 'database.sqlite' // Avoid relative paths
});Or with environment variables:
.env
DATABASE_PATH=/var/lib/myapp/database.sqliteconst sequelize = new Sequelize({
dialect: 'sqlite',
storage: process.env.DATABASE_PATH || path.join(__dirname, 'database.sqlite')
});The key is using path.join(__dirname, ...) or an explicit absolute path, not a relative path string.
SQLite cannot create the database file if its parent directory doesn't exist. Create the directory before initializing Sequelize:
const fs = require('fs');
const path = require('path');
const dbDir = path.dirname(process.env.DATABASE_PATH || './data/database.sqlite');
if (!fs.existsSync(dbDir)) {
fs.mkdirSync(dbDir, { recursive: true });
}
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: process.env.DATABASE_PATH || './data/database.sqlite'
});The { recursive: true } option creates all parent directories if they don't exist.
Ensure the application user has read/write permissions to both the database file and its parent directory:
# Make directory writable by application user
chmod 755 /path/to/database/directory
# If file exists, ensure it's readable and writable
chmod 644 /path/to/database/database.sqlite
# In Docker, use the correct user
chown -R appuser:appuser /path/to/database/
# Verify permissions are correct
ls -la /path/to/database/In Docker containers, ensure your Dockerfile doesn't run as root and that volume mounts have correct permissions:
# Create app user (not root)
RUN useradd -m -u 1000 appuser
# Set proper permissions before user switch
RUN mkdir -p /app/data && chown -R appuser:appuser /app/data
# Switch to non-root user
USER appuser
WORKDIR /app
COPY . .SQLite needs to write temporary files (WAL files, journal files) in the same directory as the database. Check available disk space and temp directory permissions:
# Check disk space
df -h /path/to/database/
# Check temp directory exists and is writable
ls -la /tmp
ls -la $TMPDIR
# On macOS, TMPDIR might be set to a custom location
echo $TMPDIRIf the disk is full or temp directory is missing:
// Configure SQLite to use a specific temp directory
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: '/path/to/database.sqlite',
dialectOptions: {
timeout: 60000 // Increase timeout if I/O is slow
}
});
// Or set the environment variable
process.env.SQLITE_TMPDIR = '/tmp';If using in-memory SQLite (useful for testing), ensure the configuration is correct:
// Correct way to use in-memory database
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: ':memory:' // Not a file path
});
// NOT: storage: 'sqlite://:memory:' // This will fail
// For persistent in-memory during session
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: ':memory:',
logging: console.log // Enable logging for debugging
});However, :memory: databases are lost when your application restarts. For testing with persistence, use a temporary file instead:
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: path.join(os.tmpdir(), 'test-db.sqlite')
});Enable detailed logging to understand exactly what path Sequelize is trying to use:
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: process.env.DATABASE_PATH || './database.sqlite',
logging: (msg) => console.log('[SQL]', msg), // Log all SQL
dialectOptions: {
timeout: 30000
}
});
// Log database connection details
sequelize.authenticate()
.then(() => {
console.log('Database connection successful');
console.log('Database path:', sequelize.options.storage);
})
.catch((err) => {
console.error('Database connection failed:');
console.error('Error:', err.message);
console.error('Expected path:', sequelize.options.storage);
// Check if path exists
const fs = require('fs');
const path = require('path');
const dbPath = sequelize.options.storage;
const dirExists = fs.existsSync(path.dirname(dbPath));
const fileExists = fs.existsSync(dbPath);
console.error('Parent directory exists:', dirExists);
console.error('Database file exists:', fileExists);
});The logging output will show you the exact path Sequelize is trying to use.
Before debugging Sequelize, test SQLite directly to isolate the issue:
const sqlite3 = require('sqlite3');
const path = require('path');
const dbPath = path.join(__dirname, 'test.sqlite');
const db = new sqlite3.Database(dbPath, (err) => {
if (err) {
console.error('SQLite connection failed:');
console.error('Error:', err.message);
console.error('Code:', err.code);
console.error('Path:', dbPath);
} else {
console.log('SQLite connected successfully');
db.serialize(() => {
db.run('CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT)');
db.run('INSERT INTO test (name) VALUES (?)', ['Hello']);
db.all('SELECT * FROM test', (err, rows) => {
if (err) console.error('Query error:', err);
else console.log('Rows:', rows);
db.close();
});
});
}
});If this works but Sequelize fails, the issue is in your Sequelize configuration, not SQLite itself.
WAL Mode and Temporary Files:
When using SQLite with WAL (Write-Ahead Logging) enabled, SQLite creates additional files:
- database.sqlite-wal: Write-ahead log
- database.sqlite-shm: Shared memory file
These files must be in the same directory as the main database file, and the directory must be writable. If the directory is read-only (common in some deployment scenarios), enable read-only mode:
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: '/readonly/path/database.sqlite',
dialectOptions: {
mode: 1 // SQLITE_OPEN_READONLY
}
});Platform-Specific Issues:
Windows: Avoid using backslashes in paths. Use path.join() or forward slashes:
// Good
const dbPath = path.join(__dirname, 'db', 'database.sqlite');
const dbPath = 'C:/Users/user/db/database.sqlite';
// Bad
const dbPath = 'C:\\Users\\user\\db\\database.sqlite'; // Escaping issuesDocker: Use volume mounts with explicit ownership:
docker run -v /host/path:/container/path:rw myappmacOS: Ensure TMPDIR is properly set:
# Check current TMPDIR
echo $TMPDIR
# If unset or problematic, set explicitly
export TMPDIR=/var/tmpLock Files and Concurrent Access:
If multiple processes access the same SQLite database simultaneously, lock timeouts can occur. Increase the timeout:
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: './database.sqlite',
dialectOptions: {
timeout: 60000 // 60 seconds, default is 5000
}
});Connection Pooling:
SQLite doesn't use traditional connection pools, but Sequelize can manage connection lifecycle:
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: './database.sqlite',
pool: {
max: 1, // SQLite works best with single connection
min: 0,
acquire: 30000,
idle: 10000
}
});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'