Triage
Confirmed against current apps/server. This is a real bug, not a duplicate of #11934.
#11940 gated the in-client update path when the running launcher is behind SERVICE_LAUNCHER_PROTOCOL (now 3) and documented local t3 update as the way to replace the launcher. That CLI path has no protocol check, and the service switch runs in the old process.
What the code does
t3 update(apps/server/src/cli/update.ts) installs the target archive, then callsBootService.install({ start: true })in this process withcliVersion: targetVersion. The comment at ~L546 is explicit: it does not go through the target’s own CLI (so downgrades to older command sets still work).install()(apps/server/src/cloud/bootService.ts~L861) writes~/.t3/runtime/service-state.jsonas{ protocol: SERVICE_LAUNCHER_PROTOCOL, activeVersion: cliVersion }— protocol is the running CLI’s compile-time constant — and points the unit at the newt3 __service-launcher.- The new launcher’s
readServiceState/decodeServiceStateaccept only its own protocol and throwService state is invalid or unsupported.There is no 2→3 migration. launchd/systemd then respawn every 5s.install()treats a successfulbootstrap/startas done andt3 updateprints success.
That matches the leftover document:
| 1 | { "protocol": 2, "activeVersion": "0.0.43-nightly.20260919.1962" } |
serviceStateActiveVersion / serviceStateHasPendingUpdate already read across protocol revisions for downgrade/pending-update guards. Decode used at launch does not. Same write path on Linux (systemd), even though this report is launchd/macOS.
apps/server/src/cli/update.test.ts does not cover a protocol bump. Remote preflight tests do (servicePreflight.test.ts blocks protocols 1 and 2).
Workaround (confirmed by the report)
After PATH is repointed at the new binary:
| 1 | t3 service install |
The new CLI rewrites service-state.json with protocol 3 and the service comes up.
Suggested fix
- Have the launcher accept and migrate compatible older state (2→3 is the same two fields). That also unsticks hosts already crash-looping.
- And/or have
t3 updatedelegate the service switch to the target CLI when protocols differ, or refuse with the existing preflight message, and not report success unless the service is actually listening.
Do not treat “run t3 update again from 0.0.42” as the fix; that is the failing path.
Accepting as a bug.