pingdotgg / pingdotgg/t3code

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

Open
#6,097 4 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
23k
Forks
5.9k
Avg merge
11h 14m
Merged PRs (30d)
357

Description

Before submitting
  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.
Area

apps/desktop

Steps to reproduce
  1. Configure and start the background server with the default T3 home (for example, t3 service install / t3 service start, listening on port 3773).
  2. Launch the desktop app as the same OS user without overriding its T3 home.
  3. The desktop sees that port 3773 is occupied, selects 3774, and starts its embedded backend.
Expected behavior

The desktop must not start a second backend against a database already owned by a running server. It should either reuse/pair with that environment or stop before opening the database and explain how to resolve the conflict.

Actual behavior

The embedded desktop backend opens the same default database, ~/.t3/userdata/state.sqlite, as the background server. Two long-lived server processes then contend for one SQLite database. Authentication, orchestration, and thread creation intermittently fail with HTTP 500 and errors such as:

Primary environment request failed during fetch-session-state (HTTP 500).
database is locked

In the observed failure, the desktop app could not finish loading and the machine became severely resource constrained until it was restarted.

Root cause

Desktop startup treats port ownership and data-directory ownership independently:

  • resolveDesktopBackendPort scans past occupied port 3773 and chooses another port.
  • The primary desktop bootstrap still passes the default environment.baseDir (normally ~/.t3) to the embedded backend.
  • Startup does not check the existing server-runtime.json lease/descriptor before opening the same database.

SQLite WAL permits concurrent readers but does not make two independent long-lived server owners safe. A busy timeout may reduce transient SQLITE_BUSY errors (see #5099), but it does not address duplicate schedulers, WebSocket streams, command processors, or resource usage.

Suggested fix

Before selecting another port or launching the embedded backend, inspect the runtime state for the selected T3 home and probe the advertised environment endpoint. If a live server already owns that home, fail closed before opening SQLite and show a specific recovery message (stop the background service, or use a separate T3 home and connect/pair with the existing environment). Ignore stale runtime state only after the probe confirms it is not live.

Add regression coverage proving that a live owner prevents embedded-backend startup while missing/stale runtime state preserves normal startup.

Impact
  • Desktop can fail to open.
  • OAuth/session and orchestration writes return HTTP 500.
  • Duplicate backends can consume substantial CPU/memory.
  • Retrying or adding busy_timeout alone masks symptoms without enforcing single ownership.
Version or commit

0.0.34-nightly.20260811.1064

Environment

Linux desktop; background T3 service and desktop app running as the same user with the default T3 home.

Workaround

Stop the background service before launching the desktop app, or launch the desktop with a separate T3 home and connect/pair to the background environment.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at resolveDesktopBackendPort and the primary desktop bootstrap, then inspect the server-runtime.json lease and advertised environment endpoint. Add regression coverage showing that a live owner blocks embedded-backend startup before the database opens, while missing or stale runtime state preserves normal startup.

Written by the indexing model from the issue text.

Assessment

Tech stack
sqlite, typescript
Domain
backend, databases, desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.