Skip to content

[Bug]: Orphaned safeStorage key makes connection-catalog.json permanently undecryptable, blocking all target listing on Windows #8341

Open

Description

@thebristolsound

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

The trigger is an Electron userData directory that gets recreated while ~/.t3/userdata survives. On Windows that happens on reinstall / profile reset / roaming-dir cleanup.

  1. Use the desktop app so at least one connection is saved. connection-catalog.json is written to %USERPROFILE%\.t3\userdata\, encrypted via safeStorage.
  2. Delete or let something recreate %APPDATA%\t3code\ (the Electron userData dir), leaving %USERPROFILE%\.t3\userdata\ intact.
  3. Launch the app. Electron generates a fresh random os_crypt.encrypted_key in the new Local State.
  4. Open Settings → Connections, or try to add/select an environment.

Expected behavior

An undecryptable catalog should degrade gracefully — treat it as "no saved connections", log a warning, and let the next write re-key the file with the current safeStorage key. Losing saved connection entries is acceptable; being unable to reach the connections UI at all is not.

Actual behavior

The connections UI is dead and no environment can be added or listed:

Could not list targets: ConnectionTransientError: Could not load the local connection catalog:
Error: Error invoking remote method 'desktop:get-connection-catalog':
DesktopConnectionCatalogStoreProtectionError: Desktop connection catalog protection failed
during decrypt-catalog at C:\Users\<user>\.t3\userdata\connection-catalog.json.

Labelled ConnectionTransientError, but it is permanent — every launch fails identically until the file is deleted by hand.

In app.asar, connectionCatalogStore.get maps any safeStorage.decryptString failure straight into a fatal DesktopConnectionCatalogStoreProtectionError, which propagates out of desktop.bootstrap. There is no fallback branch, unlike the success path that returns Option.some(decrypted):

safeStorage.decryptString(encryptedCatalog).pipe(
  Effect.mapError(
    (cause) =>
      new DesktopConnectionCatalogStoreProtectionError({
        operation: "decrypt-catalog",
        catalogPath,
        cause,
      }),
  ),
)

Root cause (verified on my machine)

The ciphertext was encrypted with an AES key that no longer exists. DPAPI itself is healthy — this is not a Windows credential problem.

  • Inner cause chain from desktop.trace.ndjson: DesktopConnectionCatalogStoreProtectionError → ElectronSafeStorageDecryptError → Error while decrypting the ciphertext provided to safeStorage.decryptString.
  • encryptedCatalog base64-decodes to a v10-prefixed blob (622 bytes: v10 + 12-byte nonce + 607 bytes ciphertext+tag), i.e. Chromium AES-256-GCM. The key lives in %APPDATA%\t3code\Local State → os_crypt.encrypted_key, DPAPI-wrapped.
  • I unwrapped that key manually with ProtectedData.Unprotect(..., CurrentUser): prefix=DPAPI blobLen=283, unprotect OK, 32-byte key. So DPAPI works and the current key is intact — it is simply a different key than the one used at encrypt time.
  • Timestamps confirm it. connection-catalog.json was written 2026-07-11 15:22. The entire %APPDATA%\t3code profile — Local State, .updaterId, Cache, GPUCache, Code Cache, Local Storage — is stamped 2026-08-08 00:17. The userData dir was recreated a month after the catalog was encrypted, generating a new random key and orphaning the file.

The underlying design issue: the catalog lives in ~/.t3/userdata but its key lives in %APPDATA%\t3code. Those two directories have independent lifecycles, so wiping either one alone leaves the app in a state it cannot recover from.

Suggested fixes

  1. Make get recover: on decrypt-catalog failure, fall back to an empty catalog, surface a non-fatal warning ("saved connections could not be decrypted and were reset"), and re-key on next write. Cheapest fix and it turns a hard block into a soft reset.
  2. Optionally move the catalog into the Electron userData dir alongside Local State, or add a plaintext key-fingerprint field so a key mismatch is detectable and self-healing rather than an exception.
  3. Reclassify — this surfaces as ConnectionTransientError, which is misleading for a permanently unrecoverable state.

Impact

Blocks work completely

Version or commit

0.0.34 (Alpha)

Environment

Windows 11 Pro build 26200 (10.0.26200), WSL2 backend (Ubuntu 24.04.4 LTS, kernel 6.18.33.2-microsoft-standard-WSL2)

Logs or stack traces

DesktopConnectionCatalogStoreProtectionError: Desktop connection catalog protection failed during decrypt-catalog at C:\Users\<user>\.t3\userdata\connection-catalog.json.
    at resources\app.asar\apps\desktop\dist-electron\main.cjs:15880:225
    at desktop.connectionCatalogStore.get (main.cjs:15886:25)
    at desktop.ipc.connectionCatalog.get (definition) (main.cjs:15905:25)
    at desktop.ipc.method (main.cjs:720:122)
    at desktop.ipc.invoke (main.cjs:669:68)
    at desktop.ipc.registerInvoke (main.cjs:27741:13)
    at desktop.ipc.installHandlers (main.cjs:28717:9)
    at desktop.bootstrap (main.cjs:28725:23) {
  [cause]: ElectronSafeStorageDecryptError: Electron safe storage failed to decrypt a string.
      at catch (main.cjs:1349:22) {
    [cause]: Error: Error while decrypting the ciphertext provided to safeStorage.decryptString.
        at try (main.cjs:1348:36)
  }
}

Workaround

Quit the app, delete (or rename) %USERPROFILE%\.t3\userdata\connection-catalog.json, relaunch, and re-add the connection. Saved connection entries are lost; clerk-tokens.json, secrets/, and state.sqlite are unaffected.

Related

Activity

  1. widingmarcus-cyber commented on Sep 25, 2026

    @widingmarcus-cyber

    Confirmed the same failure on Windows with T3 Code Alpha 0.0.42 on 2026-09-25.

    After an apparent app crash, the sidebar showed no threads. Local diagnosis found:

    • state.sqlite passed PRAGMA quick_check; the saved threads and messages were still present.
    • The local environment discovery HTTP endpoint responded with 200.
    • DesktopConnectionCatalogStore.get repeatedly failed with DesktopConnectionCatalogStoreProtectionError (decrypt-catalog), caused by ElectronSafeStorageDecryptError, then Error while decrypting the ciphertext provided to safeStorage.decryptString.
    • After a consistent SQLite backup, closing the desktop app, and renaming only connection-catalog.json aside, restart logs showed successful catalog reads. Thread/message counts were unchanged. Visual sidebar recovery has not been independently verified.

    The initial crash and reason decryption stopped working remain unconfirmed. In this case the Electron Local State file predates the catalog, so we cannot establish the profile-recreation trigger described above from timestamps alone.

    Current main (e5a46d6) still propagates this failure. A focused recovery patch is now prepared and validated locally: preserve the encrypted catalog under a unique backup filename before returning an empty catalog, allowing local discovery to proceed. Preservation failures should remain errors. This addresses the overwrite/data-loss concern on the closed #4454 rather than simply swallowing the error. No plaintext credential fallback is needed.

    Validation of the local two-file patch:

    • All 10 DesktopConnectionCatalogStore tests pass, including concurrent recovery, byte-for-byte preservation, a subsequent encrypted save, and refusal to recover if the backup rename fails.
    • The two new regression cases fail against unmodified main; the recovery case reproduces the same decrypt-catalog error chain.
    • Desktop TypeScript check, targeted lint, formatting, and git diff --check pass.
    • Catalog get/set/clear operations share a semaphore so recovery cannot rename a concurrent replacement save within the store.

    Scope is the decrypt-catalog failure only. Malformed documents, filesystem errors, and legacy migration failures retain their existing error behavior. This has not been validated in a newly packaged desktop binary, and no PR has been opened yet.

  2. AngeloTadeucci commented on Oct 3, 2026

    @AngeloTadeucci
    Contributor

    Another trigger, from V1 to V2 nightly 0.0.46-nightly.20261003.2610 on Windows 11. Upgrading reproduces this every time when the install has both %APPDATA%\t3code and %APPDATA%\T3 Code (Alpha).

    I decrypted each catalog copy offline against each profile's Local State key, unwrapping them with DPAPI and AES-GCM:

    • The V1 catalog written by 0.0.44 decrypts only with the key in %APPDATA%\t3code\Local State.
    • T3 Code (Alpha)\Local State dates from March and holds a different key.
    • The V2 migration in DesktopUserData.ts copies T3 Code (Alpha)\Local State into t3code-v2 because the Alpha profile exists. V2 then cannot decrypt the V1 catalog, and the local environment never connects. The settings page shows "Local environment is not ready yet", and no websocket is ever opened to port 3773.

    V1 resolveUserDataPath at v0.0.44 also prefers T3 Code (Alpha) when it exists, yet V1 encrypted with the t3code key. That fits the startup-ordering problem in #14265, where safeStorage loads its key before the profile path is switched. So the V2 migration copies the key V1 should have used, not the one it did use.

    Workaround: quit the app, rename ~/.t3/userdata/connection-catalog.json, and relaunch. Threads came back immediately. Saved relay connections re-pair. Suggested fix: when migrating, pick the source Local State whose key actually decrypts the existing catalog, or fall back to an empty catalog as proposed in #13656.

    @juliusmarminge

    Investigated and posted by Claude Opus 5.5 on high effort.

  3. gstamp commented on Oct 3, 2026

    @gstamp

    I hit this on Windows after upgrading to 0.0.46-nightly.20261003.2610 on October 3. An earlier nightly upgrade that day worked; immediately after the next update, all projects disappeared and no environments were connected.

    We traced this instance to the V1 → V2 Electron profile migration:

    • The installed resolveUserDataPath code creates %APPDATA%\t3code-v2\Local State, preferring %APPDATA%\T3 Code (Alpha)\Local State when it exists, and falling back to %APPDATA%\t3code\Local State.
    • Both older profiles existed on my machine.
    • The saved connection-catalog.json decrypted successfully with the key from t3code.
    • Decryption failed with the keys from both T3 Code (Alpha) and t3code-v2.

    Desktop logs repeatedly reported:

    DesktopConnectionCatalogStoreProtectionError:
    Desktop connection catalog protection failed during decrypt-catalog
    

    The local server remained healthy on 127.0.0.1:3773, reporting protocol 2 and the same nightly version. Both databases retained the project records, and the V2 database contained 68 thread records and 1,602 messages.

    Recovery was to back up the encrypted catalog, decrypt it using the working t3code key, and re-encrypt it using the current V2 key. After restarting, logs confirmed successful catalog loading, local WebSocket authentication, shell snapshot loading, and project metadata loading. No project database changes or connection resets were needed.

    This appears to be a specific migration trigger for this issue: an existing stale Alpha profile takes precedence over the profile whose key actually encrypted the shared connection catalog. Could the migration validate which source key decrypts the catalog before selecting it?

  4. J-clone commented on Oct 3, 2026

    @J-clone

    Filed the Orchestrator V2 nightly variant of this separately as #15001, since it has a distinct cause: on win32, resolveUserDataPath seeds t3code-v2\Local State from T3 Code (Alpha) whenever that folder exists, even when the catalog was encrypted with the t3code key. Decrypting connection-catalog.json manually with each profile's os_crypt.encrypted_key only succeeds with the t3code key, which matches what @AngeloTadeucci and @gstamp described above.

  5. RileyG44 commented on Oct 13, 2026

    @RileyG44

    Additional reproduction: recurring restart failure even when the persisted Windows key decrypts the catalog

    Area: apps/desktop
    Impact: Blocks work completely after affected startups.
    Observed build: 0.0.46-nightly.20261012.3035 (also observed earlier in 0.0.46-nightly.20261012.3021).
    Environment: Windows 11 Pro, x64, OS build 10.0.26200.

    This appears related to this issue and #15001, but the important difference from an orphaned-key case is that the failing catalog can still be decrypted with the existing profile key.

    Reproduction observed on this machine

    1. Start the Windows nightly and use the local environment and T3 Connect.
    2. Quit/reopen the desktop app, or restart Windows and reopen it.
    3. On affected startups, the app shows a blank white screen or does not register/list environments. The failure has recurred after several temporary recoveries. It is intermittent: some successive cold launches work, but later restarts fail again.
    4. The desktop log reports DesktopConnectionCatalogStoreProtectionError during decrypt-catalog.

    The failure also occurs with an explicit launch argument:

    "...\T3 Code (Nightly).exe" --user-data-dir="%APPDATA%\t3code-v2"
    

    The main process was verified to run under the ordinary Windows user account. An elevated process is not required to reproduce it.

    Independent decryption result

    While the desktop app is in the failed state:

    • Read os_crypt.encrypted_key from %APPDATA%\t3code-v2\Local State.
    • Remove the DPAPI prefix and unwrap it with Windows ProtectedData.Unprotect using CurrentUser.
    • Decode the catalog's encryptedCatalog value. It has the v10 prefix.
    • Decrypt its AES-GCM payload using the unwrapped key, the 12-byte nonce, and the trailing 16-byte authentication tag.

    Both the Windows key unwrap and authenticated catalog decryption succeed, and the plaintext parses as the expected connection catalog JSON. No tokens, key material, or catalog plaintext are included in this report.

    The persisted Local State file predates these failures and its modification time did not change across the observed restarts. On this machine the inspected roaming T3 profile directory was t3code-v2; a stale Alpha profile was not found. This does not establish an orphaned key or the specific migration trigger in #15001.

    Sanitized logs and checks

    desktop.connectionCatalogStore.get: Failure
    DesktopConnectionCatalogStoreProtectionError:
    Desktop connection catalog protection failed during decrypt-catalog at
    C:\Users\<user>\.t3\userdata\connection-catalog.json.
    
    desktop.ipc.connectionCatalog.get: Failure
    
    Independent persisted-key decryption: SUCCESS
    Local backend GET /health: HTTP 200
    Renderer history: created, dom-ready; renderer process remains present
    

    This separates the failure from provider login, backend availability, and a renderer crash. The exact cause of the discrepancy between independent decryption and Electron safeStorage.decryptString remains unconfirmed; an in-process key/profile initialization or caching problem is a hypothesis, not a verified root cause.

    Temporary recovery and recurrence

    With the app closed, preserve/rename only connection-catalog.json, then reopen the app. Catalog reads return successfully, the normal UI and local environment appear, and existing chats remain available. T3 Connect may need sign-in and remote route discovery again. The chat database and provider credentials were not reset, and the installed application code was not patched.

    This recovery was visually verified, but the failure returned after later restarts. Merely forcing --user-data-dir was not a durable fix.

    Latest nightly source check, 2026-10-13

    The latest Windows nightly found was v0.0.46-nightly.20261013.3066. Comparing release tags 3035...3066 showed no changes to DesktopConnectionCatalogStore.ts, DesktopUserData.ts, or DesktopClerk.ts. In the 3066 tag, DesktopConnectionCatalogStore.get still calls safeStorage.decryptString and propagates a decryption failure as DesktopConnectionCatalogStoreProtectionError, blocking catalog/bootstrap loading.

    This is a source review of 3066, not a claim that 3066 was installed or runtime-tested here.

    Please investigate why Electron rejects ciphertext that the persisted profile key successfully decrypts, and ensure a connection-catalog failure cannot block the local environment/UI bootstrap. Any recovery should preserve the encrypted original and avoid silently overwriting saved routes.

  6. serkonda7 commented on Oct 16, 2026

    @serkonda7

    I ran into this issue after upgrading from 0.0.45 to 0.1.0
    My previously added environment is missing and can not be readded.

    The Workaround is fine tho.

  7. viell-dev commented on Oct 16, 2026

    @viell-dev

    Note

    Automated comment. An AI agent (Claude Opus 5.5 via Claude Code) investigated this and wrote this comment for the affected user. The user asked for a report to be posted and answered a few follow-up questions, but has not read or reviewed this comment. Please don't treat its details as confirmed by them.

    New trigger on stable 0.1.0 (Windows): a temporary DPAPI master-key failure made Electron replace the Local State key

    Reported symptom (user's words, paraphrased): after updating to 0.1.0, T3 Connect connections and the local environment stopped working. Local agents can't be used, other machines running T3 Code can't be controlled, and the mobile app doesn't work either. The user is signed in to T3 Connect, but nothing shows under Connections. Reinstalling didn't help.

    The symptom matches this issue and #15001, but the trigger is different from #15001's Alpha-profile seeding. The #15001 workarounds (copying or re-encrypting with the t3code key) and the recovery in #20152 can't help here, because no key left on the machine can open the catalog.

    Timeline (local time; from desktop.trace.ndjson and Windows event logs)

    Time Event
    10-13 21:52 Last successful desktop.connectionCatalogStore.set, written by the previous stable build (V1 profile %APPDATA%\t3code).
    10-14 06:29 Windows Update restarts (logged as "Operating System: Upgrade"). The app was killed without a clean quit. No user signed in after the restart until 10-16.
    10-16 01:19 First Microsoft-Windows-Crypto-DPAPI/Operational event 8198: DPAPI Unprotect failed, status 0x8009000B, "Could not get the master key". No user session existed yet. 305 of these were logged between 01:19 and 01:44, and none anywhere else in the retained log.
    10-16 01:29:39 First sign-in since the Windows Update restart, made over Remote Desktop with the Microsoft account password (not domain, Entra or workplace joined). In that same second, Windows created a new DPAPI master key and set it as Preferred.
    10-16 01:30:09 The previous stable T3 Code launched. %APPDATA%\t3code\Local State was rewritten at 01:30:19, and its os_crypt.encrypted_key is now wrapped with the new master key.
    10-16 01:30:58 First decrypt-catalog failure. This happened in the old build, before the 0.1.0 update was installed.
    10-16 01:32–01:33 0.1.0 installed and seeded t3code-v2\Local State from t3code. The key is identical, so the V2 seeding was correct on this machine. The same failure then repeated on every launch.
    10-16 01:48 Reboot, then another Remote Desktop sign-in at 01:49. The old master key file was rewritten at that sign-in, and DPAPI has been healthy since.

    Diagnosis

    • On Windows, Chromium's os_crypt generates and stores a new random key when DPAPI can't unwrap the existing encrypted_key. T3 Code happened to launch during the ~25-minute DPAPI outage, so its key was replaced and the original wrapped key was lost.
    • The outage was temporary; the old master key wasn't lost. Three other Electron apps on the same account still have Local State keys wrapped with the old master key, and those keys unwrap fine today. Only T3's key references the new master key.
    • Every Local State key under %APPDATA% was tested read-only and in memory (DPAPI unwrap, then AES-256-GCM on the catalog's v10 blob). None of them, including t3code and t3code-v2, authenticates the catalog. No T3 Code (Alpha) profile exists on this machine.
    • Reinstalling doesn't help, because %USERPROFILE%\.t3\userdata and %APPDATA%\t3code* survive it.
    • Why DPAPI failed is unconfirmed. It coincided with the first sign-in after a Windows Update restart, made over Remote Desktop. The user reports that Remote Desktop sign-ins with the same Microsoft account password worked normally before. That part is outside T3. The T3-relevant point is that any temporary DPAPI failure at app launch permanently orphans the catalog and blocks the local environment.

    Fix applied

    1. Quit the app.
    2. Renamed %USERPROFILE%\.t3\userdata\connection-catalog.json to a .bak (kept, not deleted).
    3. Relaunched.

    The desktop and server traces after relaunch show:

    • desktop.connectionCatalogStore.get succeeded.
    • The backend was ready in about 5 s.
    • EnvironmentRpc requests were served and environment.orchestration.shellSnapshot succeeded.
    • environment.cloud.activateManagedTunnel and environment.cloud.health succeeded.

    The user then confirmed in the app that it works again. Saved connections in the old catalog are lost, because they can't be recovered without the original key.

    Relevance to fixes

    Only suggestion 1 in the original report covers this trigger: degrade an undecryptable catalog to empty, keep a backup and re-key on the next write. The recovery patch described above by @widingmarcus-cyber would also cover it. #20152's key recovery doesn't apply, because the original key no longer exists anywhere. Storing a plaintext key fingerprint with the catalog would also let the UI report "catalog was encrypted with a key this machine no longer has" instead of a transient-looking connection error.

    Environment: Windows 11 Pro 10.0.26300 x64. T3 Code 0.1.0 stable (latest channel), upgraded from V1 to V2 through the in-app updater.

    No keys, tokens, catalog contents, hostnames or account identifiers are included.

    🤖 Generated with Claude Opus 5.5 via Claude Code

  8. jackroberts236 commented on Oct 20, 2026

    @jackroberts236

    Confirmed the same decrypt-catalog failure on macOS after updating T3 Code Nightly. The desktop app appeared to have lost all projects and conversation history.

    Environment

    • macOS, Darwin 27.0.0, arm64.
    • Desktop app and bundled local server: 0.1.1-nightly.20261020.3399.
    • Triage CLI: 0.1.1-nightly.20261020.3399, launched with npx t3@nightly triage.

    Evidence

    • The existing statev2.sqlite still contained 10 projects, 466 legacy threads, and thousands of messages. V2 projection tables were also populated.
    • Desktop logs showed desktop.connectionCatalogStore.get and desktop.ipc.connectionCatalog.get failing with:
    DesktopConnectionCatalogStoreProtectionError:
    Desktop connection catalog protection failed during decrypt-catalog
    at ~/.t3/userdata/connection-catalog.json.
    [cause]: ElectronSafeStorageDecryptError:
    Electron safe storage failed to decrypt a string.
    [cause]: Error while decrypting the ciphertext provided to safeStorage.decryptString.
    
    • The renderer reported ConnectionTransientError: Could not load the local connection catalog.
    • Restarting the desktop app alone did not restore the projects.

    Recovery verified

    1. Quit the desktop app completely.
    2. Renamed only ~/.t3/userdata/connection-catalog.json to a backup, preserving the original encrypted file.
    3. Reopened the desktop app.

    The next catalog reads succeeded, the local server responded, and shell snapshot loading succeeded. The user confirmed that the projects and conversation history returned. The database was not modified by the triage agent. Saved remote connections may need to be registered again.

    The reason decryption stopped working is not established. This confirms the same catalog-decryption failure and empty-app symptom on macOS; it does not establish the Windows key/profile lifecycle cause described in the original report.

    Prepared via T3 triage with GPT-6 in Codex.

  9. brunocerk commented on Oct 20, 2026

    @brunocerk

    Also reproduces on macOS (arm64) with desktop Nightly 0.1.1-nightly.20261020.3399

    After two consecutive nightly updates, the desktop app showed no threads or providers, and Settings → Providers said "Connect an environment to set up its providers." The data on disk was intact.

    • connection-catalog.json was written successfully by the first update's build.
    • On the next launch, and on every launch after that, the read failed with DesktopConnectionCatalogStoreProtectionError … decrypt-catalog, caused by ElectronSafeStorageDecryptError: Error while decrypting the ciphertext provided to safeStorage.decryptString.
    • Restarting the app and rebooting the Mac didn't help.
    • Workaround, confirmed working: quit the app, rename connection-catalog.json to .bak, relaunch. The catalog read then returns Success and threads and providers are back.

    Diagnosed by Claude (claude-sonnet-5-5) in a Claude Code session, using the T3 triage playbook.

  10. juliusmarminge commented on Oct 22, 2026

    @juliusmarminge
    Member

    Triage: this is a desktop catalog-recovery bug, not a reported exploitable vulnerability. Existing work: #13656 is closed; #20152 is open and recovers catalogs when an accessible Windows profile key still matches. It does not cover a catalog whose original key is gone. Reviewed the issue and all nine comments; scanned all 943 open issues and 1,385 open PRs. No additional PR opened. No real Electron/Windows reproduction was attempted here. Escalating for maintainer review because changing encrypted credential-catalog recovery is outside the automated triage authorization; leaving this issue open.

  11. juliusmarminge commented on Oct 22, 2026

    @juliusmarminge
    Member

    Reproduced the catalog-read failure on main at 3b95e7831b: built and launched the real Electron desktop on Linux/Xvfb with isolated state and a working gnome-libsecret backend, then invoked the renderer connection-catalog IPC against undecryptable ciphertext. It rejects with DesktopConnectionCatalogStoreProtectionError during decrypt-catalog, caused by ElectronSafeStorageDecryptError. The native Windows profile-reset trigger is not verified here. No exact duplicate found in the open-issue scan; the accessible-profile-key recovery in #20152 does not cover a permanently lost key.

  12. tallboxdesign commented on Oct 23, 2026

    @tallboxdesign

    Additional Windows reproduction: intermittent restart failures through 0.1.3 Nightly

    Prepared by Codex at the affected user's explicit request. This comment includes only application behavior and sanitized technical findings; no account/device names, personal paths, network addresses, pairing codes, credentials, screenshots, or raw diagnostic bundles are attached.

    Observed versions: 0.0.42; 0.0.46-nightly.20261011.2994; 0.1.1-nightly.20261017.3238; and 0.1.3-nightly.20261023.3579. Platform: Windows x64, packaged desktop app; Nightly track for the later versions.

    Observed steps and impact

    1. Use the desktop app with a local environment and an existing paired remote environment.
    2. Close/reopen via the pinned taskbar shortcut, or restart after an in-app update.
    3. On some launches, the sidebar shows “No projects yet”, New thread is disabled, and the local environment is unavailable.
    4. Trying to add an environment fails while listing targets because the encrypted local connection catalog cannot be loaded.

    This is intermittent, not a deterministic minimal repro. A successful launch or two did not prevent recurrence on later restarts. Saved data remained present; actual project/thread deletion was not established.

    Sanitized errors

    a) Recurring failure:

    ConnectionTransientError: Could not load the local connection catalog
    DesktopConnectionCatalogStoreProtectionError:
    Desktop connection catalog protection failed during decrypt-catalog
    

    b) A launch around the update to 0.1.3-nightly.20261023.3579 also failed with:

    PrimaryEnvironmentRequestError
    Error invoking remote method 'desktop:get-local-environment-bearer-token':
    DesktopLocalEnvironmentAuthSessionBootstrapError:
    Failed to create the local desktop bearer session.
    

    Multiple desktop instances were present around that update. A causal relationship between those instances, the bearer-session error, and catalog decryption has not been established.

    Evidence and unsuccessful workarounds

    • In an earlier failing instance, the existing encrypted catalog successfully decrypted offline under the same Windows account using the stored Electron Local State key. No decrypted contents or keys are being shared.
    • Stored protected-key fingerprints in the current/legacy profile locations matched; later checks found those keys unchanged.
    • Explicitly passing the existing profile through --user-data-dir in Desktop, Start menu and pinned taskbar shortcuts allowed successful launches, but later failures recurred. A failing process was confirmed to already have that argument.
    • Seeding an alternate branded startup profile with the same existing protected key also did not prevent a later recurrence.
    • Catalog reset/rename had previously unblocked startup temporarily, but does not explain or prevent recurrence and requires re-adding saved remote entries.

    Limited local boot-ordering experiment
    On the installed 0.1.3-nightly.20261023.3579 build, a local boot-entry patch selected the existing Windows Electron userData profile synchronously before loading compileCache.cjs/main.cjs, and registered a ready handler to initialize safeStorage availability. The original application archive was backed up; the catalog was left unchanged.

    After closing the failed instances and launching the patched build, the traces reported Success for:

    • desktop.startup
    • desktop.connectionCatalogStore.get
    • desktop.localEnvironmentAuth.getBearerToken

    Existing remote projects and threads returned without resetting the catalog or re-pairing, and the user confirmed that the app worked again.

    Limits: only one fresh launch was verified after this boot patch; the planned repeated-restart tests were not completed. This supports investigating startup ordering, but does not establish the exact intermittent trigger or prove a permanent fix. An application update can overwrite the local patch.

    Expected: select the intended Windows encryption profile before anything initializes secure storage; reliably restore saved environments after restarts/updates; show an actionable recovery error rather than an apparently empty app; preserve potentially recoverable encrypted data.

    Related: #15001 and the earlier startup-ordering proposal #14265. This adds recurrence despite matching stored keys and explicit profile arguments, plus the observed 0.1.3 bootstrap failure and limited boot-ordering experiment.

  13. motelmalintzi-admin commented on Oct 24, 2026

    @motelmalintzi-admin

    Additional evidence from T3 Code 0.1.2 (packaged commit 044f072) on Windows: the same executable can work when launched from the MSIX-packaged Codex app and fail when launched from Explorer/the pinned taskbar icon.

    This appears to be another trigger for the shared-catalog/protection-profile mismatch tracked here, rather than evidence of the Alpha migration trigger in #15001.

    Observed behavior

    On the affected installation:

    1. Launch T3 as a child of a process running under the Codex desktop app. Existing chats and connections load.
    2. Close T3 completely.
    3. Launch the same installed executable by double-clicking it in Explorer. The sidebar shows “No projects yet”, and the connection catalog fails to decrypt. The user also observed the empty UI when opening the pinned taskbar icon.
    4. The underlying Windows and WSL chat databases still contain the existing data.

    This is a reproduction on an existing installation, not a clean-install recipe for creating the initial divergence.

    Profile and catalog evidence

    The executable was the same:

    %LOCALAPPDATA%\Programs\t3code\T3 Code (Beta).exe

    The two physical Electron profile locations were:

    • Normal Windows profile: %APPDATA%\t3code-v2\Local State
    • Codex package-private profile: %LOCALAPPDATA%\Packages\OpenAI.Codex_2p2nqsd0c76g0\LocalCache\Roaming\t3code-v2\Local State

    The catalog remained shared at:

    %USERPROFILE%\.t3\userdata\connection-catalog.json

    A diagnostic helper launched from Codex used GetFinalPathNameByHandleW to resolve the nominal roaming-profile path to the package-private location above. The catalog and executable did not receive that redirection. This measurement was made in the helper's inherited process context; we did not capture a file-open trace inside T3's main process.

    Both physical Local State files contained an os_crypt.encrypted_key field, and their protected values differed. That alone is not proof of different underlying AES keys, because protected wrappers can differ. No key or credential values were decrypted or printed during this comparison.

    The installed desktop bundle uses Electron safeStorage.encryptString / safeStorage.decryptString for the shared catalog. The failing Explorer launch recorded:

    DesktopConnectionCatalogStoreProtectionError: Desktop connection catalog protection failed during decrypt-catalog at %USERPROFILE%\.t3\userdata\connection-catalog.json.
    

    The path in that excerpt is redacted.

    Recovery and verification

    After closing T3 and backing up both Electron profiles and both environments' data, a narrowly scoped recovery reconciled only the protected os_crypt.encrypted_key field in the normal Local State with the working profile. Other JSON properties were preserved. Profile-specific compatibility checks included confirming that the normal profile's Cookies databases did not contain encrypted cookie values.

    Afterward:

    • Launching from Explorer loaded the Windows and WSL histories.
    • The user then closed T3 and launched it from the pinned taskbar icon. The resulting window was inspected and showed both environments' histories.
    • Both catalog reads in that taskbar launch returned Success; a subsequent launch also returned Success for both reads.
    • Database integrity checks passed. Compared thread fields, all message rows, and the checked settings files matched the backups.

    This is a description of a machine-specific recovery, not general advice to copy encryption keys between profiles. Other encrypted state can depend on a profile's key, and this recovery does not implement a product fix preventing future divergence.

    Windows and WSL were both enabled, with “WSL only” disabled. Their databases remained separate; WSL was not a second Electron profile.

    Expected behavior and limits

    Launching the same installation through different Windows launchers should not silently turn existing data into an apparently empty setup. If a protection-context mismatch prevents reading the catalog, T3 should identify the failure and provide a safe recovery path that preserves recoverable connection data.

    The observed path redirection, launcher-dependent decryption result, and successful targeted recovery support a protection-profile mismatch. The initial creation of the divergent profiles and reproduction on a clean machine remain unverified.

    No raw logs, recordings, databases, personal directory names, chat contents, or protected values are attached.

    Prepared with assistance from Codex, including GPT-6.1 Sol drafting. The investigation was conducted in an existing Codex session, not by launching a new t3 triage session.

  14. BumpyClock commented on Oct 30, 2026

    @BumpyClock

    Confirmed on Windows x64 build 10.0.26718 with T3 Code desktop and local server version 0.1.5.

    The sidebar loaded, but the main view was blank. No environments appeared, including Local, despite the local environment being enabled and its server responding.

    Desktop logs on 2026-10-29 showed:

    ElectronSafeStorageDecryptError:
    Electron safe storage failed to decrypt a string.
    
    DesktopConnectionCatalogStoreProtectionError:
    Desktop connection catalog protection failed during decrypt-catalog
    at <HOME>\.t3\userdata\connection-catalog.json.
    

    The original encryption failure trigger is unknown. Source inspection at v0.1.5 confirmed that catalog decryption failure propagates through the desktop catalog request.

    Workaround verified. Closed the app, backed up and deleted connection-catalog.json, then reopened it. The user confirmed normal operation returned. Project and chat data were untouched.

    Prepared by Codex (GPT-6), via t3 triage.

  15. Aplietexe commented on Oct 30, 2026

    @Aplietexe

    Another Windows reproduction on the v0.1.5 stable desktop app. Here the trigger was the update itself, with no manual reinstall or profile cleanup.

    Environment

    • T3 Code desktop 0.1.5 (Windows 11 x64, build 26300). The server is 0.1.5 on both the Windows backend and the WSL (Ubuntu) backend. The pre-update version is unknown.
    • Environments: local Windows and the WSL backend only, with no remote servers.

    What happened
    After the desktop auto-updated to 0.1.5, the sidebar showed "No projects yet". "Add project" only offered "Connect an environment – No connected environment can add a project". Both backends were running and answering /.well-known/t3/environment, and the WSL database still had all its projects and threads.

    Trigger (specific to this case)

    • On first launch, 0.1.5 created a new Electron profile at %APPDATA%\t3code-v2, which contains the v1-local-storage-imported marker.
    • resolveUserDataPath (apps/desktop/src/app/DesktopUserData.ts) copies Local State from %APPDATA%\T3 Code (Alpha) or %APPDATA%\t3code. Neither folder existed on this machine, so Electron generated a new os_crypt key.
    • connection-catalog.json had been written successfully by the pre-update app about 20 seconds before the update restart. Every read after the restart failed:
    ElectronSafeStorageDecryptError: Electron safe storage failed to decrypt a string.
    DesktopConnectionCatalogStoreProtectionError: Desktop connection catalog protection failed during decrypt-catalog at <home>\.t3\userdata\connection-catalog.json.
    

    Because of that, the local environments were missing too, not just saved remote ones. The upgrade path can therefore hit this with no user action. Two points worth checking for the fix:

    • Whether earlier Windows builds used a userData directory that resolveUserDataPath doesn't know about.
    • Whether the updater or uninstaller removes the old directory before the new build's first launch.

    Workaround that worked
    Quit the app fully, rename ~/.t3/userdata/connection-catalog.json, and relaunch. The app writes a fresh catalog, and the local Windows and WSL environments and all their threads came back.

    #23476 (graceful recovery with an .undecryptable backup) would have turned this into a non-event. #23470 is related, about the risk of an empty catalog overwriting the old one.

    Investigated and written by Claude Code (Claude Opus 5.5) via t3 triage; reviewed by the reporter before posting.

  16. Bbteela commented on Nov 4, 2026

    @Bbteela

    [!NOTE]

    Another Windows reproduction on stable 0.1.6, caused by a transient DPAPI master-key failure

    What happened: The user closed the desktop app and reopened it later. After that, no projects were shown and no project could be added. Updating to 0.1.7, rebooting Windows and reinstalling 0.1.6 all failed the same way.

    Diagnosis:

    • statev2.sqlite passes PRAGMA quick_check and still contains all 14 projects and 131 threads, none deleted or archived. The local server reaches 200 on /.well-known/t3/environment on every launch.
    • Every launch then fails desktop.connectionCatalogStore.get with DesktopConnectionCatalogStoreProtectionError (decrypt-catalog) → ElectronSafeStorageDecryptError.
    • The trigger is in the Windows DPAPI log. At 16:43:50Z, Microsoft-Windows-Crypto-DPAPI/Operational logged event 8198 DPAPI Unprotect failed, status 0x8009000B, together with 8203 "Master Key decryption failed because no record of this key can be found" and event 3 "Master key access failed".
      • 10 seconds later (16:44:00Z), %APPDATA%\t3code-v2\Local State was rewritten with a new os_crypt.encrypted_key. The profile itself was not recreated: uninstall_metrics.installation_date2 is still 2026-11-01 and the cache dirs keep their original dates.
      • The first decrypt-catalog failure followed at 16:44:04Z. connection-catalog.json was last written 2026-11-03, under the old key.
    • This matches the Oct 16 comment: Electron silently replaces the safe-storage key when DPAPI fails transiently, and the catalog is orphaned for good.
    • The get path in apps/desktop/src/app/DesktopConnectionCatalogStore.ts has no fallback for a decrypt failure. It is identical in v0.1.6, v0.1.7 and main (9e85538), apart from an unrelated RNG import change.
    • The web CatalogBackend for desktop (apps/web/src/connection/storage.ts:388) has no quarantine step, unlike the browser backend.

    Timeline (UTC, 2026-11-04): 16:43 reopen on 0.1.6 → 16:44 key replaced, catalog undecryptable → 16:49 update to 0.1.7 (migrations 77–79 ran at 16:50) → 16:56 Windows reboot → 17:05 reinstall of 0.1.6. Every launch failed identically.

    Environment: Windows 11 Home x64 (10.0.26300). T3 Code desktop with its bundled local server, 0.1.6 → 0.1.7 → 0.1.6. Local server exposed on the network with Tailscale Serve enabled. Triage CLI 0.1.7.

    Workaround (confirmed): Quit the app, then rename %USERPROFILE%\.t3\userdata\connection-catalog.json. On the next launch all projects and threads came back and adding projects worked again. Saved outbound connections must be re-added; the inbound pairing from the Mac is unaffected.

    Suggestion: Treat a decrypt-catalog failure as an empty catalog, and move the unreadable file aside (as #23470 proposes) instead of failing on every launch.

  17. LiquidBacn commented on Nov 5, 2026

    @LiquidBacn

    Confirmed on Windows 11 x64 (10.0.26200) with packaged desktop and bundled local server 0.1.8-nightly.20261104.4192, on November 4, 2026. The user also encountered the same screen on stable before switching to nightly; the exact stable and pre-upgrade versions are unknown. They were returning after several months and upgrading an older installation.

    The current user-facing symptom blocks the entire app: immediately after launch, the full-window first-run recovery screen says “Still connecting — T3 Code could not confirm this workspace.” No projects or settings are accessible.

    Evidence from this installation:

    • Desktop traces repeatedly show desktop.connectionCatalogStore.get and desktop:get-connection-catalog failing with DesktopConnectionCatalogStoreProtectionError during decrypt-catalog, caused by ElectronSafeStorageDecryptError.
    • The bundled backend starts successfully. Database migrations through migration 79 completed, and read-only queries found 5 active projects and 137 non-deleted V2 threads, with no recorded legacy-import errors.
    • The encrypted catalog was last modified August 21. The reason it stopped decrypting was not established; no encryption-key inspection was performed.

    Recovery was confirmed: with the app closed, rename only connection-catalog.json to a dated backup and reopen. Desktop traces then show successful catalog reads, and server traces show the WebSocket connection opening. The user confirmed their projects and chats returned, including the expected older history. No database edits or application patches were made.

    This adds a current-nightly confirmation and the full-window onboarding failure presentation to the existing reports. The generic workspace-confirmation message initially suggested a database migration problem, although the observed blocker was catalog decryption.

    Prepared by Codex (GPT-6.1 Sol), via t3 triage, at the affected user's request.

  18. Foniass commented on Nov 7, 2026

    @Foniass

    Another Windows reproduction on stable 0.1.7, this time triggered by a full Windows reset followed by restoring a backed-up ~/.t3.

    Environment

    • T3 Code desktop 0.1.7, Windows 11 Pro x64 (10.0.26300). The bundled local server is 0.1.7 (/.well-known/t3/environment returns 200 with the same environmentId as before the reset).
    • Environments: the local Windows backend plus the desktop-managed WSL (Ubuntu) backend. ~/.t3 was also restored inside WSL.

    What happened

    1. The user backed up %USERPROFILE%\.t3, reset Windows, reinstalled T3 Code, and restored .t3 to the same location.
    2. On first launch the desktop showed no projects and no environment. The machine was not listed as an environment at all.

    Diagnosis

    • statev2.sqlite is intact: 11 projects, 180 threads.
    • Every launch fails desktop.connectionCatalogStore.get → DesktopConnectionCatalogStoreProtectionError (decrypt-catalog) → ElectronSafeStorageDecryptError. A Windows reset destroys the DPAPI keys that protected the old safeStorage key, so the restored catalog and its .bak-* copies can never be decrypted on this install.
    • This is a natural, common path into this bug: anyone who backs up and restores .t3 across an OS reinstall will hit it. The restored catalog is undecryptable by design, so get should degrade to an empty catalog (keeping the old file aside, as fix(desktop): keep an unreadable connection catalog instead of overwriting it #23488 proposes) instead of failing every launch.

    Workaround (confirmed)
    With the app closed, rename %USERPROFILE%\.t3\userdata\connection-catalog.json to connection-catalog.json.unreadable-<date> and relaunch. The local environment and all its projects came back, and the desktop-managed WSL backend also reconnected without manual re-pairing.

    Diagnosed with t3 triage by Claude Code (Claude Opus 5.5).

  19. Supernor commented on Nov 9, 2026

    @Supernor

    Another reproduction of the MSIX-parent trigger described by @motelmalintzi-admin above, this time with the Claude desktop app instead of Codex.

    Environment: T3 Code 0.1.7 (stable), Windows 11 10.0.26300, Claude desktop 4.23118.0 (package anthropicpbc.claude_fnn82j28hfe8t).

    Controlled comparison, same installed exe and same connection-catalog.json (hash unchanged during the failing run):

    Launch method desktop.connectionCatalogStore.get SSH environment
    Direct child of a shell inside the Claude app (5 launches) Success, 5 of 5 Connected, 5 of 5
    Start menu shortcut through explorer.exe, parent process explorer (4 launches) Failure (decrypt-catalog), 4 of 4 Not attempted

    A failed launch never reaches ensureEnvironment, so the saved SSH environment doesn't connect and the app comes up partly loaded. This looks intermittent to a user, because the result depends only on what launched the app.

    Profile evidence: from a process started outside the package, %APPDATA%\t3code-v2\Local State and %LOCALAPPDATA%\Packages\anthropicpbc.claude_fnn82j28hfe8t\LocalCache\Roaming\t3code-v2\Local State hold different os_crypt.encrypted_key values (compared by hash only). From inside the package, the %APPDATA% path resolves to the package copy, so the mismatch is invisible when diagnosing from an agent running in that app. Microsoft-Windows-Crypto-DPAPI/Operational logged no events during these runs, so this was not a transient DPAPI failure.

    Machine-specific recovery: with T3 closed, I renamed the normal profile and copied the package profile over it, excluding caches. Afterward, 6 of 6 launches succeeded and connected: 2 from inside the Claude app and 4 through explorer.exe. This is not general advice, since other state encrypted under the old key can be lost.

    Any Windows user who has an MSIX-packaged agent app start T3 can hit this, and those apps are a common way to run T3. The catalog is shared across launchers but its key isn't, so a fix likely needs to detect the mismatch and offer recovery, as #23470 proposes.

    No logs, databases, personal paths or key material are attached.

    Investigated with Claude Code (Opus 5.5).

  20. Chenalejandro commented on Nov 12, 2026

    @Chenalejandro

    Another reproduction, this time on Linux, with a different trigger: the desktop app's own relaunch after a change to the server exposure setting.

    Environment

    • T3 Code desktop 0.1.9 (stable AppImage, launched directly), bundled local server 0.1.9
    • Fedora 45, kernel 7.3.3, x64, COSMIC desktop
    • Secret Service provided by oo7-daemon (with oo7-portal); Chromium os_crypt in Local State shows the portal backend with prev_init_success: true

    What happened

    1. While setting up Tailscale, I changed Settings → server exposure to network-accessible. The app relaunched itself (desktop.lifecycle.relaunch, 17:27:40). A t3code child process dumped core (SIGTRAP), and the app came back up fine.
    2. I enabled Tailscale Serve on port 443 (desktop.serverExposure.setTailscaleServeEnabled, 17:28:28). The app relaunched again, and again a t3code process dumped core (SIGTRAP).
    3. On the next start (17:28:38), oo7-daemon logged create_item{label="Chromium Safe Storage" replace=true} for application=t3code. That means Electron didn't find its existing key and generated a new one. Earlier launches that day logged only the Chrome Safe Storage Control unlock probe and decrypted the catalog fine. No other T3 safe-storage item remains in the keyring.
    4. From then on, every launch fails with DesktopConnectionCatalogStoreProtectionError … during decrypt-catalog (cause ElectronSafeStorageDecryptError). The app shows "No projects yet", and adding a project or starting a thread doesn't work. Settings → Environments shows Local environment enabled and no saved remote environments. connection-catalog.json was last written at 17:24, before the key changed.

    State at the time

    • statev2.sqlite intact: 18 projects, 193 threads
    • /.well-known/t3/environment returns 200 (serverVersion 0.1.9)
    • The only startup errors are the usual 503s while the backend boots, plus tailscale serve timed out after 10000ms on the server side

    Workaround
    With the app closed, I renamed ~/.t3/userdata/connection-catalog.json to a backup name and relaunched. The local environment, projects and threads came back immediately. The only thing lost was the saved remote connections in the old catalog, which were already unreadable.

    Notes

    • On Linux/oo7, a key mismatch can come from a crashing self-relaunch, not only from a userData reset on Windows. The graceful fallback this issue proposes (treat an undecryptable catalog as empty, warn, and re-key on the next write) would have avoided the outage completely.
    • I didn't confirm why the relaunched process missed the existing key.

    Investigated with t3 triage by Claude Code (Claude Opus 5.5).

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions