# t3 service install silently rebinds an existing service to a different base dir, orphaning its data · Issue \#23858 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/issues/23858)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: backlog

Priority: 0

## Description

[Discussion and activity](https://git.cafe/pingdotgg/t3code/issues/23858)

---

### What happened

> I was working with t3 in headless mode for weeks, connecting to this machine from my other laptop, tablet, phone. Today I decided to install desktop app on this machine. Once I did connect to the service I noticed the pop up saying the t3 server can be updated so I clicked update. All was fine and dandy but I noticed I can't open my files anymore. So I went to terminal to check the service status which said service is corrupted and can be fixed with `t3 service install`. Once I installed the service all my sessions and projects disappeared.

### Diagnosis

The user's long-lived service was installed with `--base-dir /mnt/workspace/Projects`, so the unit's `T3CODE_HOME` pointed there and all state (685 threads, 6 projects, 704MB `statev2.sqlite`) lived under that base dir. The default `~/.t3` held only leftovers from first-day experiments. The server's self-update (0.0.46-nightly.20261005.2689 → 0.1.2-nightly.20261022.3526) completed fine.

The data "disappeared" because of two compounding behaviors when a `t3` CLI is run **without** `--base-dir` against a unit installed **with** one:

1. **`t3 service status` reports a healthy foreign-base-dir unit as needing repair.** In `apps/server/src/cloud/bootService.ts`, `status` compares the on-disk unit against `detectedManager.render(plan)` where `plan` is rendered for the CLI's own `input.baseDir` (default `~/.t3`). A unit installed for a different base dir can never match, so `current` is false and the CLI prints "needs an update or repair / Next: Run `t3 service install` to repair it." `status` even computes `installedBaseDir` from the unit, but neither uses it in the `current` comparison nor surfaces it in `formatServiceStatus`.

2. **`t3 service install` overwrites the unit without comparing base dirs, and its downgrade guard reads the wrong state file.** `install` reads `previousStateText` from `statePath` under the CLI's `input.baseDir` (`~/.t3/runtime/service-state.json`, which said `0.0.46-nightly.20261005.2702` — equal to the CLI, so no refusal) instead of the unit's actual base dir (`/mnt/workspace/Projects/runtime/service-state.json`, which said `0.1.2-nightly.20261022.3526`). It then stops the running service and rewrites the unit for `~/.t3`. The real instance is silently replaced by a server bound to an empty state dir — to the user, total data loss.

Notably, `restart` and `uninstall` both already guard on this exact condition (`bootServiceBaseDirOf(unit)` vs `path.resolve(input.baseDir)`) and refuse to touch a foreign unit. `install` — the only destructive one of the three — has no such guard. Verified at tag `v0.0.46-nightly.20261005.2702` (cfa4f765) and still present on `main` as of 2026-10-22.

Suggested direction: give `install` the same `installedBaseDir` comparison and refuse (or require an explicit flag) when it differs; read the downgrade-guard state from the unit's base dir; and print `installedBaseDir` in `t3 service status` so the mismatch is visible instead of being reported as corruption.

### Steps to reproduce

1. `t3 service install --base-dir=/some/other/dir` and use the server (create a thread).
2. Install a second `t3` CLI (e.g. a distro package) and run `t3 service status` with no flags → reports "needs an update or repair" although the service is healthy.
3. Run `t3 service install` with no flags, as the status output suggests.
4. The unit is rewritten for the default `~/.t3`; the original instance stops and the service now serves an empty state dir. All sessions/projects appear gone. No downgrade or mismatch warning is shown even when the replaced service was newer than the CLI.

### Version

Service that was clobbered: 0.1.2-nightly.20261022.3526 (self-updated from 0.0.46-nightly.20261005.2689). CLI that clobbered it: 0.0.46-nightly.20261005.2702 (AUR `t3code-nightly-bin`). Missing guard confirmed on `main`.

### Environment

Linux x64 (CachyOS, kernel 7.2.9-2), Node v26.8.2, systemd user service.

### Evidence

```
# Unit after `t3 service install` (no --base-dir) — rebound to default home:
Environment=T3CODE_HOME=~/.t3
ExecStart=~/.t3/runtime/versions/0.0.46-nightly.20261005.2702/t3 __service-launcher

# Real instance, cleanly shut down at the moment of the reinstall:
# /mnt/workspace/Projects/userdata/logs/boot-service.log
[21:22:41.924] INFO: Server update prepared; handing off to the service launcher.
[21:22:47.756] INFO: Listening on http://127.0.0.1:3773
[22:14:57.696] INFO: V2 orchestration shutdown reconciliation completed

# /mnt/workspace/Projects/runtime/service-state.json (ignored by the downgrade guard):
{ "protocol": 3, "activeVersion": "0.1.2-nightly.20261022.3526",
  "update": { "fromVersion": "0.0.46-nightly.20261005.2689",
              "targetVersion": "0.1.2-nightly.20261022.3526", "status": "committed" } }

# Replacement server booting on the stale default-home state:
# ~/.t3/userdata/logs/boot-service.log
[22:14:59.774] WARN: Database migration history diverges from this build; recorded
                     migration ids are skipped, not reconciled by name.
```

### Related issues

#5749 (SSH reconnect can replace an external T3 service with a competing managed runtime) is the same family — one T3 install clobbering another's service ownership — but a different entry point and mechanism; this one is driven by the `service status` → `service install` repair suggestion ignoring `installedBaseDir`.

### Fix applied or workaround

Recovered on the user's machine with no data loss: removed the manual systemd override, then ran the pinned runtime's own CLI — `/mnt/workspace/Projects/runtime/versions/0.1.2-nightly.20261022.3526/t3 service install --base-dir=/mnt/workspace/Projects`. Workaround until fixed: always pass `--base-dir` to `t3 service ...` commands when the service was installed with one.

### Filed by

Claude Fable 5 (claude-fable-5) via `t3 triage` (Claude Code)

