Summary
devtunnel create <id> chooses the cluster by nearest-by-latency. On a host roughly
equidistant between two clusters, the "nearest" pick is unstable between runs, so repeated
create of the same tunnel id lands it in different clusters on different runs —
producing two distinct tunnels that share one id (id is unique per cluster). Because the
public URL encodes the cluster (https://<id>-<port>.<cluster>.devtunnels.ms), the URL
also changes when the cluster flips, silently invalidating anything that persisted it
(webhooks, OIDC redirect URIs).
Repro
On a host where two clusters report near-identical ping (e.g. a box in Helsinki sees
uks1 and euw within a few ms — devtunnel clusters --ping):
devtunnel create my-tunnel # run 1 -> my-tunnel.uks1
devtunnel delete my-tunnel.uks1
devtunnel create my-tunnel # run 2, minutes later -> my-tunnel.euw (nearest flipped)
Without an explicit delete, re-running create/host from tooling across the flip leaves
both my-tunnel.uks1 and my-tunnel.euw present.
Why it matters
- Unstable public URL. A URL registered with an external service (Azure Bot Service
messaging endpoint, OAuth redirect, webhook) breaks when the cluster flips, with nothing
in the caller's config having changed.
- Silent duplicates. Bare-name operations on a duplicated id then behave ambiguously —
a host can attach to one cluster while a lookup resolves the other.
- This is the root cause behind microsoft/aspire#14111,
where .NET Aspire's DevTunnels integration (which shells bare-name create) inherits the
flap.
Suggestions (any one would resolve it)
- Make a tunnel id sticky to its cluster: once
<id> exists in some cluster, a later
bare create <id> reuses/targets that cluster instead of re-running nearest-routing.
- Honour the persisted default cluster (
devtunnel set / CurrentClusterId) on create.
- Add hysteresis to nearest-cluster selection so a near-tie doesn't flip run to run.
(A documented create-time cluster override — --service-uri, see the companion docs issue
#643 — lets callers opt out, but the default behaviour is still the
trap.)
Environment
- devtunnel CLI
1.0.1824+9e602bae78, Linux x64, Microsoft Entra ID auth.
Summary
devtunnel create <id>chooses the cluster by nearest-by-latency. On a host roughlyequidistant between two clusters, the "nearest" pick is unstable between runs, so repeated
createof the same tunnel id lands it in different clusters on different runs —producing two distinct tunnels that share one id (id is unique per cluster). Because the
public URL encodes the cluster (
https://<id>-<port>.<cluster>.devtunnels.ms), the URLalso changes when the cluster flips, silently invalidating anything that persisted it
(webhooks, OIDC redirect URIs).
Repro
On a host where two clusters report near-identical ping (e.g. a box in Helsinki sees
uks1andeuwwithin a few ms —devtunnel clusters --ping):Without an explicit delete, re-running
create/hostfrom tooling across the flip leavesboth
my-tunnel.uks1andmy-tunnel.euwpresent.Why it matters
messaging endpoint, OAuth redirect, webhook) breaks when the cluster flips, with nothing
in the caller's config having changed.
a host can attach to one cluster while a lookup resolves the other.
where .NET Aspire's DevTunnels integration (which shells bare-name
create) inherits theflap.
Suggestions (any one would resolve it)
<id>exists in some cluster, a laterbare
create <id>reuses/targets that cluster instead of re-running nearest-routing.devtunnel set/CurrentClusterId) oncreate.(A documented create-time cluster override —
--service-uri, see the companion docs issue#643 — lets callers opt out, but the default behaviour is still the
trap.)
Environment
1.0.1824+9e602bae78, Linux x64, Microsoft Entra ID auth.