Main process crashes with SQLITE_BUSY on new APPLICATION_SHARED storage (.vscode-shared\sharedStorage\state.vscdb) when two instances run concurrently
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
## Does this issue occur when all extensions are disabled?
Yes (root-caused in core, not extension-related — see analysis below)
## Steps to Reproduce
1. Open VS Code (stable, v1.127.0) normally.
2. While it's running, open a second, independent VS Code window/instance shortly after (e.g. a second `Code.exe` process launching close in time to the first).
3. Within a few minutes, one or both windows crash with an uncaught main-process exception.
## Observed behavior
`main.log` shows the application starts up fine and successfully creates/initializes the new application-shared storage database:
```
2026-07-06 20:49:32.077 [info] StorageMainService: creating application shared storage
2026-07-06 20:49:32.280 [info] [shared storage] Creating shared storage database at 'C:\Users\\.vscode-shared\sharedStorage\state.vscdb' (wasCreated: false)
2026-07-06 20:49:32.282 [info] [shared storage] Initializing fallback application storage (path: C:\Users\\AppData\Roaming\Code\User\globalStorage\state.vscdb)
2026-07-06 20:49:32.348 [info] [shared storage] Fallback application storage initialized with 245 items
2026-07-06 20:49:32.356 [info] update#setState idle
...
2026-07-06 20:53:26.085 [error] [storage state.vscdb] transaction(): Error: SQLITE_BUSY: database is locked
2026-07-06 20:53:26.088 [error] [uncaught exception in main]: Error: SQLITE_BUSY: database is locked
2026-07-06 20:53:26.088 [error] Error: SQLITE_BUSY: database is locked
```
The failure happens ~4 minutes after successful startup, during an ordinary write **transaction** (not the initial DB open/creation), which strongly suggests a second, independent OS process was concurrently writing to the same `state.vscdb` file at that moment.
## Root cause analysis (from source, commit `4fe60c8b1c`, v1.127.0)
- `C:\Users\\.vscode-shared\sharedStorage\state.vscdb` is the new `APPLICATION_SHARED` storage scope added in #311317 ("Add `APPLICATION_SHARED` storage scope for cross-app state sharing"), implemented by `ApplicationSharedStorageMain` in [`src/vs/platform/storage/electron-main/storageMain.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/platform/storage/electron-main/storageMain.ts). It is explicitly designed to be shared **across separate processes** (VS Code and a companion "Agents" app).
- The underlying `SQLiteStorageDatabase` in [`src/vs/base/parts/storage/node/storage.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/base/parts/storage/node/storage.ts) only retries once on `SQLITE_BUSY` when **opening** the DB connection (`connect()`, 2s `BUSY_OPEN_TIMEOUT`), with this comment:
> "SQLITE_BUSY should only arise if another process is locking the same DB we want to open at that time. This typically never happens because a DB connection is limited per window."
That assumption no longer holds for `ApplicationSharedStorageMain`, since it is intentionally opened by multiple independent processes.
- Crucially, the ongoing `transaction()` method (used for every subsequent read/write after the DB is open) has **no busy-retry/backoff logic at all** — a `SQLITE_BUSY` there just calls `handleSQLiteError()` and rejects the promise. That rejection appears to end up as an unhandled rejection reaching `process.on('unhandledRejection')` in [`src/vs/platform/telemetry/electron-main/errorTelemetry.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/platform/telemetry/electron-main/errorTelemetry.ts), logged as `[uncaught exception in main]`, and the process/window subsequently crashes.
- Additionally, `ApplicationSharedStorageMain.doCreate()` constructs `SQLiteStorageDatabase` without a `busyTimeout` option, so `PRAGMA busy_timeout` is never set for this shared DB — SQLite has no chance to wait/retry internally before surfacing `SQLITE_BUSY` on lock contention between the two processes.
## Suggested fix
- Set a `busyTimeout` (`PRAGMA busy_timeout=`) when opening `ApplicationSharedStorageMain`'s `SQLiteStorageDatabase`, since it is the one scope explicitly meant for multi-process access.
- Add retry-on-`SQLITE_BUSY` handling to `transaction()` (not just the initial `connect()`), at least for the `APPLICATION_SHARED` scope.
- Ensure a `SQLITE_BUSY` in this path can't escalate to an uncaught/unhandled exception that crashes the process.
## Environment
- VS Code version: 1.127.0 (stable), commit `4fe60c8b1cdac1c4c174f2fb180d0d758272d713`
- OS: Windows
- `sharedDataFolderName`: `.vscode-shared` (from `product.json`)
I searched existing issues for `SQLITE_BUSY`, `"database is locked"`, and `ApplicationSharedStorage` and didn't find an existing report of this specific crash — apologies in advance if this duplicates something I missed.
Contributor guide
Assessment
This issue has not been assessed yet.