Repository navigation
[Bug]: Service update leaves T3 Connect relay targeting stale origin port #7458
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
- Run T3 Code as the installed user systemd service on a remote Linux VM and expose it through T3 Connect.
- Upgrade the desktop app and allow the managed VM runtime/service to update. In this case, the macOS desktop app was 0.0.33, the shell CLI remained 0.0.32, and the managed runtime had installed 0.0.33.
- Attempt to reconnect to the remote environment from the desktop app.
- Inspect
t3 service status, listeners, andboot-service.log.
The service reported needs an update or repair. The active T3 server listened on 127.0.0.1:3773, while the existing managed Cloudflare tunnel continued forwarding to an old ephemeral origin port (127.0.0.1:35765).
Expected behavior
A managed runtime/service update should atomically restart or reconcile the background service and relay connector. The tunnel origin should always point to the currently active T3 server port, and saved clients should reconnect without manual operator intervention.
Actual behavior
The desktop app could not connect and repeatedly displayed:
Failed to connect. Reconnecting...
Reason: Relay environment endpoint is unavailable: endpoint_request_failed
The relay itself was provisioned and t3 connect status showed exposure enabled, but Cloudflared repeatedly failed to reach its stale origin. The server logs also showed invalid saved-session/bootstrap credentials during reconnect attempts.
Impact
Blocks work completely
Version or commit
Desktop app 0.0.33; managed VM runtime/service 0.0.33; shell CLI 0.0.32 before repair
Environment
macOS desktop client connecting to a Linux Coder VM over T3 Connect; Node v24.19.0; user-level systemd service
Logs or stack traces
$ t3 service status
T3 Code service
Status: needs an update or repair
Next: Run `npx t3@latest service update`.
$ ss -lntp
LISTEN 127.0.0.1:3773 # active T3 server
cloudflared: Unable to reach the origin service: dial tcp 127.0.0.1:35765: connect: connection refusedWorkaround
Run npx t3@latest service update with access to the user systemd bus, then explicitly restart t3code.service. After restart, T3 0.0.33 listened on port 3773, Cloudflared was relaunched against the live origin, and an outside-in relay health request returned HTTP 200.
One additional wrinkle: from a non-interactive Coder SSH shell, the first service repair could not access the user systemd bus (Failed to connect to bus: No medium found). Setting XDG_RUNTIME_DIR=/run/user/$(id -u) and DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus allowed the service command to inspect the installed unit. This may be worth handling or surfacing explicitly.
Activity
Dawsson commentedon Aug 19, 2026
I apologize for the lack of human input on this, I have no idea where to even start with this issue
Dawsson commentedon Aug 19, 2026
This reproduced again roughly 80 minutes after the first repair, and it also affected a separate desktop-managed macOS environment at the same time.
New evidence:
127.0.0.1:3773.127.0.0.1:37337).t3code.servicecausedCloudManagedEndpointRuntimeto create a new tunnel/connector and restored the public relay health endpoint to HTTP 200.endpoint_request_failederror after the desktop app and connector had been running continuously for about two days.CloudManagedEndpointRuntime.reconcileConfig, replaced the managed connector, and restored that relay health endpoint to HTTP 200 as well.This recurrence suggests the issue is not limited to a partially upgraded systemd service. It appears that relay configuration can drift to a dead ephemeral origin while the actual backend and connector processes remain healthy. No environment IDs, relay hostnames, tunnel IDs, or credentials are included here.
vidhunv1 commentedon Aug 24, 2026
I'm having this same issue, it happens very frequently and have to restart the service to recover. There is some config difference between the server port and the remotely managed tunnel. For me, it was 32913.
tayyabfareed commentedon Aug 27, 2026
Reproduced on a desktop-managed macOS environment, including after updating and restarting into T3 Code Nightly
0.0.36-nightly.20260827.1205.This case differs slightly from the stale local-origin-port case in the original report: the active managed tunnel is healthy and demonstrably reaches the current backend on port 3773, but relay status/connect still returns
endpoint_request_failedwithout a request arriving at the tunnel.Reproduction / recovery attempts
cloudflaredprocess were running; removed a duplicate backend/tunnel created during troubleshooting.0.0.34through0.0.36-nightly.20260827.1205.npx t3 connect status --jsonreturnedlinked: false,cloudUserId: null,relayUrl: null, and publishing off.The failure persists:
Diagnostics
3773.cloudflared2026.5.2has four active HA connections.cloudflared_tunnel_request_errorsis0./api/t3-connect/healthreaches the backend and returns the expected HTTP 400, proving the public hostname routes to the live origin.cloudflared_tunnel_total_requestsand do not appear in the server trace. This suggests failure/stale state before the relay request reaches the managed endpoint, rather than an origin-port mismatch.invalid_dpop; the complete unlink/relink should have replaced that stale credential, but desktop relay connectivity remains blocked byendpoint_request_failed.Latest trace ID from Nightly 1205:
Earlier trace IDs from the same investigation:
No environment IDs, managed hostnames, tunnel IDs, account IDs, or credentials are included here. This was collected through
npx t3 triage --agent codexplus direct local checks.sheepbun commentedon Sep 6, 2026
Reproduced on a plain single-machine Linux setup — no VM/Coder hop and no desktop app involved, so the drift isn't limited to the multi-host update scenarios above.
Environment
0.0.38(stable), user-level systemd service (t3code.service,Restart=always)7.2.3-arch1-2), Nodev26.8.1npx t3in an interactive terminal (which also manages the background service)What happened
The background service crash-looped for several restart cycles after a fresh
npx t3install (unrelated root cause — the node-pty install-script issue tracked in #7475), then finally came up and stayed running. That surviving process landed on a different local port than the last time the environment had linked with the relay (the CLI's own port picker falls back to a random available port whenever the default3773is occupied, which it was during the crash-loop churn).From then on:
boot-service.logshowed the startup path logging "T3 Connect desired link reconciled on startup" with no error — i.e. the reconcile call it makes on every boot did run and did not fail.cloudflaredkept loggingUnable to reach the origin service ... dial tcp 127.0.0.1:<old-port>: connect: connection refusedagainst the previous session's port, indefinitely (observed for 20+ minutes with zero recovery, until we intervened).Relay could not reach the environment endpoint (endpoint_request_failed)the whole time.Fix that worked:
systemctl --user restart t3code.service. The restart spawned a brand-new relay-client/tunnel connector (new tunnel ID observed in the logs) which immediately registered against the current port with no further warnings. Same workaround already documented above for the VM/desktop cases.Possible mechanism (from reading
apps/server/src/cloud/ManagedEndpointRuntime.tsandapps/server/src/cloud/http.tson this version): the per-boot reconcile (reconcileDesiredCloudLink) does re-provision the relay side with the current origin, butCloudManagedEndpointRuntime.reconcileConfig's dedup key (runtimeConfigKey) only hashesproviderKind+connectorToken+tunnelId+tunnelName— it never includes the origin host/port. So when the same tunnel identity is reused across a reconcile, the already-running localcloudflared tunnel runprocess is left untouched even if the origin it should be forwarding to has changed, and there's nothing else here that forces it to reconnect or verifies it actually converged on the new target. That would explain why a full service restart (which tears down and respawns the connector unconditionally) reliably fixes it, while the routine startup-time reconcile does not.Diagnosed via
t3 triage(Claude Sonnet 5).KrtinShet commentedon Oct 1, 2026
Reproduced on macOS (launchd service), 0.0.44, with a deterministic trigger
Environment: T3 Code 0.0.44 (CLI, service runtime and desktop app), macOS arm64 (Darwin 27.0.0), Node v26.8.2, cloudflared 2026.5.2 (managed install). Background service via launchd (
t3 serveon127.0.0.1:3773), desktop app with local environment disabled, linked to T3 Connect with a managed tunnel.Repro:
127.0.0.1:3773, remote clients work).t3as the same user with the defaultT3CODE_HOME. It starts a second web-mode server on an ephemeral port against the same state dir.T3 Connect · Reconnecting: Relay could not reach the environment endpoint (endpoint_request_failed).indefinitely.Diagnosis: the ad-hoc server shares the service's secrets and environment link, so its startup path (
registerManagedCloudTunnelRecovery(localOrigin),apps/server/src/server.ts:868) asks the relay to reconcile the tunnel ingress to its own ephemeral port. When it exits, the ingress stays on that port. The service only registers its origin at startup, so it never corrects it, and its cloudflared child keeps forwarding to the dead port.Evidence (UTC, 2026-10-01):
T3 Connect managed tunnel recovery registered(port 3773)server.mode=web, server.port=51865;environment.cloud.registerManagedCloudTunnelRecoverysucceeds at 09:58:24releaseManagedTunnelOnShutdownfails:upstream_unavailable, trace ID20b251b9f693c559ae637a4922753a65Unable to reach the origin service … dial tcp 127.0.0.1:51865: connect: connection refused … originService=http://127.0.0.1:51865t3on port 52657;registerManagedCloudTunnelRecoveryfails withrelay returned HTTP 504(Ray IDa43aa3258f08fd81-SIN), yet from 10:03:39 the ingress isoriginService=http://127.0.0.1:52657, so the origin change was applied despite the 504lsof: onlyt3 servelistens, on127.0.0.1:3773;t3 connect statusshows exposure enabled and link provisionedWorkaround:
t3 service restartre-registers 3773. Verified here: after the restart at 10:16:16 the service loggedT3 Connect managed tunnel recovery registeredat 10:17:24 and cloudflared reported no further origin errors.Suggestions: an ad-hoc
t3should not re-register the managed tunnel origin when a service owns the T3 home (overlaps #6097), and/or the service should re-reconcile its origin when its connector reports repeatedconnection refusedto a port that is not its own.Produced via
t3 triageby Claude Opus 5.5 (claude-opus-5-5) in Claude Code.DigitalWestern commentedon Oct 11, 2026
Reproduced on Linux (Fedora 44, x64) with the systemd service on
0.0.46-nightly.20261008.2849. In my case the stale port has a concrete trigger: a second T3 server launched over SSH by the macOS desktop app.What happens
t3code.serviceserver listens on127.0.0.1:3773and owns the T3 Connect managed tunnel.~/.t3/ssh-launch/<id>/run-t3.sh. It shares the same T3 home, so it also shares the same T3 Connect link and tunnel.findAvailablePort(apps/server/src/cli/config.ts) gives the SSH-launched server 3774. On startup it callsregisterManagedTunnelRecoverywith origin127.0.0.1:3774, and the relay switches the tunnel's ingress to 3774.dial tcp 127.0.0.1:3774: connect: connection refusedfor every request, and mobile showsRelay could not reach the environment endpoint (endpoint_request_failed).Evidence
server.logshowsListening on http://127.0.0.1:3774followed byT3 Connect managed tunnel recovery registered(last at 23:17, it stopped at 23:24). The phone failed from then on.systemctl --user restart t3code.servicefixes it right away: the public/api/t3-connect/healthreaches the backend again (HTTP 400 for an unauthenticated probe) and the 3774 errors stop.Repro
endpoint_request_failed.Possible directions: the SSH-launched server shouldn't run the managed tunnel or register an origin when another server on the host already owns the link. Or the tunnel owner could re-assert its origin when cloudflared reports origin connection failures.
Mobile trace IDs:
f68867e720322ef82c798d215ec5567e,e8e8d71d4868e441ae24c8e1f0937fdeDiagnosed and written by Claude Opus 5.5 (Claude Code) via
t3 triage.