Skip to content

fix(desktop): prevent shared database ownership - #6098

Draft
matheustimbo wants to merge 1 commit into
pingdotgg:mainfrom
matheustimbo:agent/desktop-single-db-owner
Draft

fix(desktop): prevent shared database ownership#6098
matheustimbo wants to merge 1 commit into
pingdotgg:mainfrom
matheustimbo:agent/desktop-single-db-owner

Conversation

@matheustimbo

@matheustimbo matheustimbo commented Aug 11, 2026

Copy link
Copy Markdown

What

  • add a desktop bootstrap preflight for the selected T3 state directory
  • read the existing server-runtime.json owner record before scanning for another port
  • confirm both the recorded PID and the T3 environment descriptor before blocking startup
  • surface a specific recovery message instead of opening the shared SQLite database
  • preserve normal startup for missing, malformed, dead, or non-T3 runtime records

Why

When the background service already listens on port 3773, the desktop currently scans to 3774 but still launches its embedded backend with the same default T3 home. Both long-lived servers then open userdata/state.sqlite, causing database is locked HTTP 500s and duplicate resource usage.

This enforces a single live backend owner for a desktop state directory. A SQLite busy timeout can reduce transient contention, but it cannot make duplicate schedulers, command processors, and WebSocket streams safe.

Impact

Users who launch the desktop while a background service owns the same T3 home now get a clear startup error with safe recovery instructions. They can stop the service or use a separate T3CODE_HOME and connect to the running environment.

Checks

  • pnpm exec vp test run apps/desktop/src/backend/DesktopBackendDatabaseOwner.test.ts apps/desktop/src/app/DesktopAppErrors.test.ts — 2 files, 6 tests passed
  • pnpm exec vp run --filter @t3tools/desktop typecheck — passed
  • targeted vp fmt --check — passed
  • git diff --cached --check — passed

Fixes #6097

Model: GPT-5 Codex
Harness: Codex desktop app

Note

Prevent desktop backend startup when another T3 server owns the database

  • Adds DesktopBackendDatabaseOwner.ensureDesktopBackendDatabaseAvailable in DesktopBackendDatabaseOwner.ts, a pre-start guard that checks whether a previously recorded server process is still alive and serving a live T3 backend.
  • The guard reads a persisted runtime owner record from the state directory, checks PID liveness via process.kill(pid, 0), and probes /.well-known/t3/environment on the recorded origin with a 2s timeout.
  • If all checks pass (process alive, endpoint responds 200), startup is aborted with a structured DesktopBackendDatabaseOwnedError containing the origin, PID, and state directory.
  • This guard is called in DesktopApp.ts during bootstrap, before the backend starts.
  • Risk: if the liveness probe is slow or the state file is stale but not cleaned up, startup may be blocked unnecessarily.
📊 Macroscope summarized 971ce3f. 2 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 531512e1-abdd-4e27-8f76-db5b0fd9e376

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 11, 2026
return;
}

if (!(yield* probeT3Server(owner.origin))) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High backend/DesktopBackendDatabaseOwner.ts:97

When probeT3Server returns false (probe failure or 2-second timeout), ensureDesktopBackendDatabaseAvailable returns successfully and lets the desktop proceed — but the owning process may still be alive and holding the database. A starting or transiently slow T3 server can fail the probe while already owning the SQLite database, so this preflight allows a second backend to launch against the same database, reintroducing the lock/duplicate-processor conflict it is meant to prevent. Consider failing (or blocking until the probe succeeds) when the owner process is alive but the probe does not confirm a healthy server, rather than treating a failed probe as safe.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/desktop/src/backend/DesktopBackendDatabaseOwner.ts around line 97:

When `probeT3Server` returns `false` (probe failure or 2-second timeout), `ensureDesktopBackendDatabaseAvailable` returns successfully and lets the desktop proceed — but the owning process may still be alive and holding the database. A starting or transiently slow T3 server can fail the probe while already owning the SQLite database, so this preflight allows a second backend to launch against the same database, reintroducing the lock/duplicate-processor conflict it is meant to prevent. Consider failing (or blocking until the probe succeeds) when the owner process is alive but the probe does not confirm a healthy server, rather than treating a failed probe as safe.

}

const owner = runtimeOwner.value;
if (!(input.isProcessAlive ?? defaultIsProcessAlive)(owner.pid)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High backend/DesktopBackendDatabaseOwner.ts:93

ensureDesktopBackendDatabaseAvailable can block desktop startup on a stale runtime file even when no live server owns the state directory. The PID check only verifies that some process with owner.pid is alive, and the HTTP probe only verifies that some T3 server is reachable at owner.origin — the two checks are independent and never confirm that the live process is the one serving at that origin. PID reuse by an unrelated process and port reuse by a different T3 server make both checks pass, triggering a false DesktopBackendDatabaseOwnedError. If this loose coupling is acceptable, consider documenting the rationale; otherwise, bind the checks together (for example, have the probed server report its own PID and compare it to owner.pid).

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/desktop/src/backend/DesktopBackendDatabaseOwner.ts around line 93:

`ensureDesktopBackendDatabaseAvailable` can block desktop startup on a stale runtime file even when no live server owns the state directory. The PID check only verifies that *some* process with `owner.pid` is alive, and the HTTP probe only verifies that *some* T3 server is reachable at `owner.origin` — the two checks are independent and never confirm that the live process is the one serving at that origin. PID reuse by an unrelated process and port reuse by a different T3 server make both checks pass, triggering a false `DesktopBackendDatabaseOwnedError`. If this loose coupling is acceptable, consider documenting the rationale; otherwise, bind the checks together (for example, have the probed server report its own PID and compare it to `owner.pid`).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Desktop starts a second backend against the background service database

1 participant