mastra-ai/mastra · error
${file} is in use by another process — is another Mastra Cod
Error message
${file} is in use by another process — is another Mastra Code session running? Close other sessions and run /prune vacuum again. What it means
reclaimLibSQLDisk compacts a SQLite/libsql database file by VACUUMing it into a copy. Before compaction it probes the file's journal-mode header; a healthy single-process database must read 'delete'. If the header says otherwise (e.g. 'wal'), another process has the database open, and vacuuming/compacting under it would corrupt or orphan data, so the operation is refused.
Source
Thrown at mastracode/sdk/src/utils/storage-maintenance.ts:178
// does not finalize outstanding statements — they are only finalized by
// GC, so lock release after close() is nondeterministic. Reported as
// https://github.com/tursodatabase/libsql-js/issues/228 (fix in flight in
// PR #214). Once that lands, the header check can become a plain
// journal_mode query.
const probe = new Database(file);
try {
probe.exec('PRAGMA busy_timeout = 2000');
// Round-trip through WAL so the probe also works when a clean shutdown
// already left the file in rollback mode.
probe.exec('PRAGMA journal_mode = WAL');
probe.exec('PRAGMA journal_mode = DELETE');
} catch {
// busy — the header check below reports the failure
} finally {
probe.close();
}
if (journalModeFromHeader(file) !== 'delete') {
throw new Error(
`${file} is in use by another process — is another Mastra Code session running? ` +
`Close other sessions and run /prune vacuum again.`,
);
}
// Native `libsql` driver, not `@libsql/client`: the wrapper's close() can
// leave the file lock held in-process (cached statements), which would
// block other connections afterwards. This connection stays in rollback
// mode, so even a pinned statement holds no lock once we're done.
const db = new Database(file);
try {
db.exec('PRAGMA busy_timeout = 2000');
const pageSize = pragmaNumber(db, 'page_size');
const pageCount = pragmaNumber(db, 'page_count');
const freelistCount = pragmaNumber(db, 'freelist_count');
const liveBytes = Math.max(0, pageCount - freelistCount) * pageSize;
const { bsize, bavail } = statfsSync(dirname(file));
const freeBytes = bsize * bavail;
if (freeBytes < requiredFreeBytes(liveBytes)) {View on GitHub (pinned to 75dd419e61)
Solutions
- Close every other Mastra Code session and any process with the file open (check with `lsof <file>`), then run /prune vacuum again
- Remove stale sidecars only after confirming no process holds the db: delete `<file>-wal` and `<file>-shm`
- Retry the vacuum in a single dedicated terminal while no dev server is running
Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync } from 'node:fs';
const header = readFileSync(dbFile).subarray(18, 19).toString(); // journal-mode byte: 1=delete(rollback), 2=wal
if (header === String.fromCharCode(2)) {
throw new Error('Database is in WAL mode — another process likely has it open. Close sessions before vacuum.');
} Type guard
const isRollbackMode = (file: string): boolean => readFileSync(file).subarray(18, 19).toString() === String.fromCharCode(1);
Try / catch
try {
await maintenance.results();
} catch (e) {
if (String(e.message).includes('is in use by another process')) {
console.error('Close other Mastra sessions (check `lsof <db>`) and re-run the vacuum.');
} else throw e;
} Prevention
- Run /prune vacuum from a single dedicated terminal with no dev servers or watchers on the project
- Check `lsof <db-file>` before vacuuming to confirm nothing holds the file
- Delete stale -wal/-shm sidecars only after confirming no live owner
When it happens
Trigger: Running /prune vacuum (createStorageMaintenance → reclaimLibSQLDisk) while another Mastra Code session, dev server, or any SQLite/libsql client has the same storage file open in WAL mode; or a crashed session left stale -wal/-shm sidecars and a lingering open handle.
Common situations: Two mastracode TUI sessions sharing one project storage file; a `mastra dev` server left running in another terminal; an IDE SQLite extension holding the db; a previous vacuum crashed leaving WAL sidecars.
Related errors
- ${file} was opened by another process during compaction — is
- Not enough free disk space to compact ${file}: need ${format
- MastraFactory.prepare() called twice
- Factory kickoff lease was lost before completion.
- Failed to swap compacted copy into place AND failed to resto
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/daab3af3cde09f42.
Report an issue: GitHub.