pingdotgg / pingdotgg/t3code

[Bug]: Desktop startup stalls for 15-20s on multi-project setups due to synchronous git fetch and unindexed SQLite query before window creation

Open
#12,617 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

accepted bug via-triage
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/server

Steps to reproduce
  1. Use T3 Code desktop with multiple registered projects (e.g. 20-30 repositories) and default settings ("defaultAutoPull": true).
  2. Accumulate thread activity history (e.g. 10k+ rows in projection_thread_activities).
  3. Quit the app and launch t3code / t3code-nightly on desktop.
  4. Measure wall-clock time between launching the process and the main application window appearing.
Expected behavior

The desktop application window should appear within 1-2 seconds of launching. Long-running network operations (such as remote git fetching across all projects) and startup state reconciliations should run asynchronously in the background rather than blocking the desktop HTTP readiness probe and window creation.

Actual behavior

The application process starts immediately, but no window appears for 15-22 seconds (giving the impression that the app failed to launch or crashed). Once the window finally appears, the app runs fast and responsively.

Root cause analysis:

  1. Window creation is blocked on HTTP readiness: In apps/desktop/src/backend/DesktopBackendManager.ts, the desktop main process probes GET /.well-known/t3/environment before apps/desktop/src/window/DesktopWindow.ts calls createWindow().
  2. Global middleware blocks all HTTP traffic: In apps/server/src/server.ts, commandReadinessLayer intercepts all HTTP requests and waits on startup.awaitCommandReady before serving any route.
  3. Heavy synchronous operations in apps/server/src/serverRuntimeStartup.ts block commandGate.signalCommandReady:
    • "projects.auto-pull" (line 976): autoPullProjects() iterates through every workspace root with defaultAutoPull enabled (the default in DEFAULT_SERVER_SETTINGS) and calls git.statusDetails(cwd) in batches of 4. This triggers refreshStatusUpstreamIfStale -> fetchRemoteForStatus (network git fetch) for each project sequentially. On setups with ~25 repositories, this takes 7-10 seconds over WiFi.
    • "worktree-setups.reconcile" (line 973): reconcileWorktreeSetups calls query.listActivitiesByKind("worktree-setup"). In apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts, this executes:
      SELECT a.* FROM projection_thread_activities a
      JOIN projection_threads t ON t.thread_id = a.thread_id
      WHERE a.kind = ? ...
      
      There is no index on kind in projection_thread_activities. In databases with 15k+ activities and heavy payload_json columns, this full scan and temporary B-tree sort takes 6+ seconds.
  4. Because the desktop probe timeout is 1000ms, the probe repeatedly times out with HTTP 499 until all startup phases complete ~15s later.
Related issues and why this is not a duplicate
  • #2726: Reported a general slow desktop startup on 0.0.24, attributed to provider CLI probing and closed as resolved. This report covers the newer projects.auto-pull (introduced in PR #9277) and the unindexed worktree-setups.reconcile query added in recent releases.
  • PR #9277: Intended autoPullProjects to be non-blocking ("failures are non-blocking for startup and status refresh"), but placed it synchronously ahead of commandGate.signalCommandReady (line 1063). Because commandReadinessLayer gates /.well-known/t3/environment, it blocks createWindow in DesktopBackendManager.ts.
  • PR #10972: Attempted to defer auto-pull and splash earlier on Linux, but was closed unmerged on September 18 without addressing the unindexed SQL query or the architectural readiness gate.
  • #9239 / #9246: Linux keyring / safe-storage stall; our credential store completes in <3ms.
  • #8949: Runtime shellSnapshot repository identity caching after UI is open; our issue occurs before window creation and includes a 6.6s database query.
  • #10517: Backend crash-loop on macOS (ECONNREFUSED); our backend does not crash, but is held by synchronous startup phases.
Impact

Major degradation or frequent failure

Version or commit

0.0.43-nightly.20260919.1962 (commit dfbb11bdd7c3), also observed across previous releases.

Environment

Arch Linux / Linux x86_64, Electron Desktop

Logs or stack traces
# From desktop.trace.ndjson:
13:27:37.750 | desktop.backendProcess.probeReadiness (15558.9ms)
13:27:38.724 | http.client GET /.well-known/t3/environment (1001ms) -> Interrupted / Timeout
... (13 retries timing out after 1000ms each) ...
13:27:53.054 | http.client GET /.well-known/t3/environment (195ms) -> 200 OK
13:27:53.252 | desktop.window.createWindow (55ms)  # Window finally opens after 15.5s

# From server.trace.ndjson:
13:27:39.475 | server.startup.worktree-setups.reconcile (6637ms): sql.execute (no index on projection_thread_activities.kind)
13:27:46.112 | server.startup.projects.auto-pull (6976ms wall-clock, 118.5s cumulative across 4 threads):
               GitVcsDriver.fetchRemoteForStatus across 25 repositories
13:27:53.054 | commandGate.signalCommandReady
Workaround
  1. Setting "defaultAutoPull": false in ~/.t3/userdata/settings.json eliminates the 7-second network Git fetching phase during boot.
  2. Adding CREATE INDEX IF NOT EXISTS idx_projection_thread_activities_kind ON projection_thread_activities(kind); drops the worktree reconciliation query from ~6.6s to <1ms.

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 with apps/desktop/src/backend/DesktopBackendManager.ts and apps/desktop/src/window/DesktopWindow.ts, then trace commandReadinessLayer in apps/server/src/server.ts into serverRuntimeStartup.ts. Inspect ProjectionSnapshotQuery.ts and the startup trace timings, including the auto-pull and worktree reconciliation phases. Done means desktop window creation no longer waits on the reported long-running startup work and the reproduction startup timing improves without breaking readiness behavior.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.