🔧 Error Fixes
· 2 min read
Last updated on

Bun: SQLite Error — Database Is Locked or Not Found


SQLiteError: database is locked

What causes this

Bun has a built-in SQLite driver (bun:sqlite) that’s fast but comes with SQLite’s inherent limitations. The “database is locked” error means another connection or process is writing to the database and SQLite can’t handle concurrent writes.

Common causes:

  • Multiple processes or workers writing to the same SQLite file simultaneously
  • A long-running write transaction blocking other writes
  • The database file is on a network filesystem (NFS, SMB) which doesn’t support SQLite’s locking
  • A crashed process left a stale lock file (database.db-wal, database.db-shm)
  • The database path doesn’t exist (for “not found” errors)

Fix 1: Enable WAL mode

Write-Ahead Logging dramatically improves concurrent access:

import { Database } from 'bun:sqlite';

const db = new Database('mydb.sqlite');
db.exec('PRAGMA journal_mode = WAL');

WAL mode allows multiple readers while one writer is active. It’s the single most impactful fix for SQLite concurrency.

Fix 2: Use a single database connection

Don’t create multiple Database instances for the same file:

// ❌ Multiple connections cause locking issues
function getUser(id: number) {
  const db = new Database('mydb.sqlite');
  return db.query('SELECT * FROM users WHERE id = ?').get(id);
}

// ✅ Reuse a single connection
const db = new Database('mydb.sqlite');
db.exec('PRAGMA journal_mode = WAL');

function getUser(id: number) {
  return db.query('SELECT * FROM users WHERE id = ?').get(id);
}

Fix 3: Add busy timeout

Tell SQLite to wait instead of immediately failing:

const db = new Database('mydb.sqlite');
db.exec('PRAGMA busy_timeout = 5000'); // wait up to 5 seconds

Fix 4: Remove stale lock files

If a process crashed, it may have left lock files:

# Check for lock files
ls -la mydb.sqlite*

# If the database isn't in use, remove the WAL files
rm mydb.sqlite-wal mydb.sqlite-shm

Only do this when you’re sure no process is using the database.

Fix 5: Fix the database path

For “not found” errors:

import { Database } from 'bun:sqlite';
import { existsSync, mkdirSync } from 'fs';
import { dirname } from 'path';

const dbPath = './data/mydb.sqlite';

// Ensure the directory exists
mkdirSync(dirname(dbPath), { recursive: true });

// create: true creates the file if it doesn't exist
const db = new Database(dbPath, { create: true });

Fix 6: Don’t use SQLite on network filesystems

SQLite’s locking doesn’t work reliably on NFS or SMB:

// ❌ Network path
const db = new Database('/mnt/shared/mydb.sqlite');

// ✅ Local path
const db = new Database('./data/mydb.sqlite');

If you need shared access across machines, use PostgreSQL or MySQL instead.

How to prevent it

  • Always enable WAL mode — there’s almost no reason not to
  • Use a single database connection per process, exported from a shared module
  • Set PRAGMA busy_timeout to handle brief lock contention gracefully
  • Keep SQLite databases on local filesystems, never on network mounts
  • For high-concurrency apps, consider switching to PostgreSQL — SQLite is best for single-process or low-write workloads