{"record":{"id":"daab3af3cde09f42","repo":"mastra-ai/mastra","slug":"file-is-in-use-by-another-process-is-another","errorCode":null,"errorMessage":"${file} is in use by another process — is another Mastra Code session running? Close other sessions and run /prune vacuum again.","messagePattern":"(.+?) is in use by another process — is another Mastra Code session running\\? Close other sessions and run /prune vacuum again\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/utils/storage-maintenance.ts","lineNumber":178,"sourceCode":"    // does not finalize outstanding statements — they are only finalized by\n    // GC, so lock release after close() is nondeterministic. Reported as\n    // https://github.com/tursodatabase/libsql-js/issues/228 (fix in flight in\n    // PR #214). Once that lands, the header check can become a plain\n    // journal_mode query.\n    const probe = new Database(file);\n    try {\n      probe.exec('PRAGMA busy_timeout = 2000');\n      // Round-trip through WAL so the probe also works when a clean shutdown\n      // already left the file in rollback mode.\n      probe.exec('PRAGMA journal_mode = WAL');\n      probe.exec('PRAGMA journal_mode = DELETE');\n    } catch {\n      // busy — the header check below reports the failure\n    } finally {\n      probe.close();\n    }\n    if (journalModeFromHeader(file) !== 'delete') {\n      throw new Error(\n        `${file} is in use by another process — is another Mastra Code session running? ` +\n          `Close other sessions and run /prune vacuum again.`,\n      );\n    }\n    // Native `libsql` driver, not `@libsql/client`: the wrapper's close() can\n    // leave the file lock held in-process (cached statements), which would\n    // block other connections afterwards. This connection stays in rollback\n    // mode, so even a pinned statement holds no lock once we're done.\n    const db = new Database(file);\n    try {\n      db.exec('PRAGMA busy_timeout = 2000');\n      const pageSize = pragmaNumber(db, 'page_size');\n      const pageCount = pragmaNumber(db, 'page_count');\n      const freelistCount = pragmaNumber(db, 'freelist_count');\n      const liveBytes = Math.max(0, pageCount - freelistCount) * pageSize;\n      const { bsize, bavail } = statfsSync(dirname(file));\n      const freeBytes = bsize * bavail;\n      if (freeBytes < requiredFreeBytes(liveBytes)) {","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/utils/storage-maintenance.ts#L160-L196","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { readFileSync } from 'node:fs';\nconst header = readFileSync(dbFile).subarray(18, 19).toString(); // journal-mode byte: 1=delete(rollback), 2=wal\nif (header === String.fromCharCode(2)) {\n  throw new Error('Database is in WAL mode — another process likely has it open. Close sessions before vacuum.');\n}","typeGuard":"const isRollbackMode = (file: string): boolean =>\n  readFileSync(file).subarray(18, 19).toString() === String.fromCharCode(1);","tryCatchPattern":"try {\n  await maintenance.results();\n} catch (e) {\n  if (String(e.message).includes('is in use by another process')) {\n    console.error('Close other Mastra sessions (check `lsof <db>`) and re-run the vacuum.');\n  } else throw e;\n}","preventionTips":["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"],"tags":["sqlite","concurrency","file-lock","vacuum"],"backgroundTag":"database-file-locked","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}