How to fix Sequelize ConnectionError: SQLITE_CANTOPEN in SQLite
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.
Quick fix
Fixes SQLITE_CANTOPEN
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
});- Use an absolute file path instead of relative path
- Ensure the parent directory exists
- Fix file permissions on database and directory
- Check disk space and temp directory
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});Sequelize ConnectionError: SQLITE_CANTOPEN
What this error means
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.
Typical symptoms
- Sequelize connection fails immediately with "SequelizeConnectionError: SQLITE_CANTOPEN"
- Application crashes on startup when initializing Sequelize
- Error mentions "unable to open database file"
- Works on Linux/Mac but fails on Windows (or vice versa)
- Permissions error occurs when running with restricted user
- Docker/container environment reports SQLITE_CANTOPEN on volume mounts
Common causes
- Database file path does not exist and parent directory is missing
- Incorrect relative path causing Sequelize to look in wrong directory
- Insufficient permissions on database file or parent directory
- Database directory is not writable by the application user
- Using relative path without understanding working directory context
- Windows drive letter issues when specifying cross-drive paths
- Database locked or corrupted from previous crash
- Disk full or quota exceeded preventing file creation
- Temporary directory (used by SQLite for WAL/journal files) is not writable
How to fix "Sequelize ConnectionError: SQLITE_CANTOPEN"
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.
Advanced notes
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
}
});Frequently asked questions
- What does "SQLITE_CANTOPEN" mean?
- 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.
- How do I fix "SQLITE_CANTOPEN"?
- 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.
- What causes "SQLITE_CANTOPEN"?
- Database file path does not exist and parent directory is missing Incorrect relative path causing Sequelize to look in wrong directory Insufficient permissions on database file or parent directory
- Is the "SQLITE_CANTOPEN" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- 📚SQLite Official Documentation
- 🐙github.com - 3551(GitHub)
- 📖sqlite.org - rescode(Official Docs)
- 🐙github.com - 3629(GitHub)
- 📝
- 🐙github.com - files(GitHub)
- 🐙github.com - 1863(GitHub)