[Bug]: `t3 update` across a service-launcher protocol bump leaves the service crash-looping ("Service state is invalid or unsupported") while reporting success
Nobody has claimed this yet.
- 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
- macOS, background service installed on t3 0.0.42 (service launcher protocol 2).
- Run
t3 update --channel nightly --yesto 0.0.43-nightly.20260919.1962 (service launcher protocol 3). - The update reports success:
Background service restarted on 0.0.43-nightly.20260919.1962.
Expected behavior
The service starts on the new version, or the update refuses with a clear message before touching the service.
Actual behavior
The service never comes up. launchctl print gui/$UID/com.t3tools.t3code.service shows state = spawn scheduled, last exit code = 1, and launchd respawns it every 5 s indefinitely. Nothing listens on the port; every paired client is disconnected until someone intervenes on the server machine.
~/.t3/runtime/service-state.json after the update:
{ "protocol": 2, "activeVersion": "0.0.43-nightly.20260919.1962" }
Root cause:
t3 updateperforms the service switch in the old CLI's process (apps/server/src/cli/update.ts~L545: "The service switch runs in this process against the target version … rather than through the target's own CLI").install()then writesservice-state.jsonwith the old CLI's compile-timeSERVICE_LAUNCHER_PROTOCOL(apps/server/src/cloud/bootService.ts~L861) while pointing the unit at the new binary.- The new launcher's
readServiceState(apps/server/src/serviceLauncher.ts~L186) rejects any protocol other than its own and throwsService state is invalid or unsupported.There is no forward migration.
#11940 added a preflight that blocks the in-client (remote) update path under a legacy launcher, but the CLI update path, which docs/user/background-service.md recommends, has no such check.
Suggested fixes:
- Have the launcher accept and migrate older state documents when the shape is compatible (protocol 2 → 3 is the same two fields).
- Or have
t3 updatedelegate the service switch to the target version's CLI when the protocols differ, or refuse with the same message the remote preflight uses.
Impact
Blocks a workflow (the background service is down until manually repaired; the update reports success)
Version or commit
0.0.42 → 0.0.43-nightly.20260919.1962
Environment
macOS 26.6 (Darwin 25.6.0), arm64, background service via launchd
Logs or stack traces
# boot-service.log, repeating every 5 s
[service-launcher] Service state is invalid or unsupported.
[service-launcher] Service state is invalid or unsupported.
[service-launcher] Service state is invalid or unsupported.
Workaround
Run t3 service install with the newly installed CLI. It rewrites service-state.json with the new protocol and the service starts.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/server/src/cli/update.ts around line 545 and apps/server/src/cloud/bootService.ts around line 861; trace how the old CLI switches to the target service version and writes service-state.json. Then inspect apps/server/src/serviceLauncher.ts around line 186 and compare the protocol handling with the preflight from #11940. Done means a protocol-bump update starts the target service successfully or refuses before changing it with a clear message.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100