Skip to content

[Bug]: Desktop app hangs in silent background crash loop and blocks subsequent launches if backend fails startup migrations #15139

Closed as not planned

Description

@AlonResearch

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. Have a local state.sqlite where projection_threads is missing settled_at / settled_override (e.g., from an interrupted migration or schema desync where migration 033_ProjectionThreadsSettled did not run).
  2. Launch the desktop application (T3 Code (Alpha).exe).
  3. The backend server child process fails migration 046_RepairAutomaticSettlementTimestamps with Error: no such column: thread.settled_at and exits.
  4. The Electron desktop app never renders a window and does not show an error dialog; instead, it enters an infinite retry loop in the background, repeatedly trying to respawn the backend child process every ~12 seconds.
  5. While these background processes spin, try launching T3 Code again (via Desktop shortcut or Start Menu). Because the background process holds the single-instance lock (app.requestSingleInstanceLock()), the new instance forwards the launch request to the zombie instance and terminates immediately.
  6. To the user, the app appears completely dead and unresponsive, silently refusing to open after install.

Expected behavior

  1. Recovery Dialog / Clean Exit: If the backend child process crashes during startup or fails the HTTP readiness probe (waitForHttpReady), the desktop app should display an error dialog or crash screen (e.g., notifying the user of the failure and providing a button to inspect ~/.t3/userdata/logs or back up and reset state.sqlite). If unrecoverable, it should release the single-instance lock and terminate rather than lingering as a zombie process.
  2. Defensive Migrations: Migrations such as 046_RepairAutomaticSettlementTimestamps should defensively verify table columns (e.g. PRAGMA table_info(projection_threads)) before executing raw UPDATE queries that assume earlier schema alterations succeeded, matching the defensive patterns used in migrations 045, 047, etc.

Actual behavior

No window is ever created. The main process silently loops in the background consuming CPU and holding the Chromium single-instance lock, blocking all future launches until killed manually via Task Manager.

Impact

Blocks work completely

Version or commit

0.0.40 – 0.0.45

Environment

Windows 11 x64, T3 Code Desktop (Electron)

Logs or stack traces

{"message":"backend child process failure output start","level":"ERROR","annotations":{"component":"desktop-backend-child","phase":"START","details":"port=3773"}}
{"message":"backend child process output","level":"INFO","annotations":{"component":"desktop-backend-child","stream":"stdout","text":"ERROR (#5): MigrationError: Migration \"46_RepairAutomaticSettlementTimestamps\" failed\n    at runMigrations (resources/server.asar/apps/server/dist/bin.mjs:54374:9) {\n  [cause]: effect/sql/SqlError: Failed to prepare statement {\n    [cause]: effect/sql/SqlError/UnknownError: Failed to prepare statement {\n      [cause]: Error: no such column: thread.settled_at\n          at try (resources/server.asar/apps/server/dist/nodeSqliteClient.mjs:479:18)\n    }\n  }\n}"}}
{"message":"backend child process failure output end","level":"ERROR","annotations":{"component":"desktop-backend-child","phase":"END","details":"code=1"}}

Workaround

  1. Terminate all stuck background processes: Stop-Process -Name "T3 Code (Alpha)" -Force.
  2. Inspect ~/.t3/userdata/logs/server-child.log for the exact SQL migration failure.
  3. Either back up and remove ~/.t3/userdata/state.sqlite to let the app generate a fresh database, or manually alter projection_threads to add the missing columns (settled_at, settled_override, snoozed_at, snoozed_until) so migration 46 and subsequent migrations can complete.

Activity

  1. juliusmarminge commented on Oct 3, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks @AlonResearch for the detailed write-up and the child-process log! The desktop failure is real, and it's already tracked as #10517 (open). The migration 46 error is what triggered that bug for you, so I've marked this as a duplicate.

    Desktop

    On 0.0.40 through 0.0.45, and on current main, a primary backend that exits during startup gets restarted with no limit while desiredRunning is set. The delay starts at 500ms and caps at 10s (DesktopBackendManager.ts), which fits the roughly 12-second retries you saw. Nothing on that path shows a dialog, because onPreflightFailed only covers WSL preflight and fatal Electron startup.

    The main window isn't created until the primary backend is HTTP-ready (createMainIfBackendReady / waitingForBackend in DesktopWindow.ts), and the connecting splash only appears in WSL-only mode (DesktopApp.ts). On Windows, that means no window at all.

    The Clerk bridge takes Electron's profile single-instance lock at startup (DesktopClerk.ts). A later launch isn't the primary instance, so it quits. The second-instance handler only reveals a BrowserWindow if one already exists. With no window, every later launch does nothing until the stuck process is killed.

    That's the same gap as #10517. Open PR #10523 targets it: after five primary crashes, it stops retrying and shows a native dialog with the child error plus Retry and Quit. The dialog doesn't need a window, so it would cover this Windows case too.

    Migration 46

    46_RepairAutomaticSettlementTimestamps updates projection_threads.settled_at and filters on settled_override without checking that those columns exist. When they're missing, the statement fails, the child exits with code 1, and the desktop loop above starts. That's the failure in your log.

    An interrupted 033_ProjectionThreadsSettled wouldn't leave the database in this state. The migrator writes the journal row and runs the migration in one transaction, and rolls back if it fails. Migration 46 only runs when the highest recorded id is below 46, so 033 was skipped, not half-applied. The migrator skips every id at or below its high-water mark without comparing names. That's the slot-collision behavior described in #8896 (closed).

    A PRAGMA check that skips the update wouldn't add the missing columns, and later reads (including the V1 thread importer) still select thread.settled_at, so they'd fail the same way. Migrations 033, 034, 045, and 047 guard their own ADD COLUMN, not a later repair update. Open PR #9312 re-applies a skipped migration and warns on slot collisions. Open PR #14202 turns an id clash into a single clear startup error instead of a crash loop.

    On 0.0.40 through 0.0.45 the file is userdata/state.sqlite. Current main copies it once to statev2.sqlite and migrates the copy, so the same migration 46 failure can still stop a V2 boot when the copied journal skipped 033. A maintainer will decide on the fix direction.

    Your workaround is fine for getting unstuck locally: kill T3 Code (Alpha), then either add the missing columns or start from a fresh database (back up state.sqlite first).

  2. added
    bugSomething is broken or behaving incorrectly.
    duplicateThis issue or pull request already exists
    via-triageFiled through npx t3 triage
    on Oct 3, 2026
  3. t3dotgg commented on Oct 14, 2026

    @t3dotgg
    Member

    Note

    🤖 Claude Opus 5.5 responding on behalf of Theo

    Closing as a duplicate of #10517, as triaged above. The silent restart loop after a backend fails at startup is tracked there. The migration failure that triggered it for you is a separate cause. If it still happens on a current nightly, please open a new issue with the migration error.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.duplicateThis issue or pull request already existsvia-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions