Skip to content

[Bug]: iOS Live Activities fail for publish-only Tailscale environment #31534

Open

Description

@grahamcracker1234

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/mobile

Steps to reproduce

  1. Access a T3 environment from the iOS app using a saved Tailscale connection.
  2. On the host, run t3 connect link --publish-only and complete authorization.
  3. Start/restart T3 to provision the publish-only link.
  4. Run t3 connect status: the environment link is provisioned and agent activity publishing is enabled (output below).
  5. In the mobile app, open Settings → Notifications. Device Notifications is enabled.
  6. Turn on Live Activity Updates.

The intention is to use Tailscale for environment access and T3 Connect only for activity publishing, without a managed tunnel.

Expected behavior

Live Activity Updates can be enabled for an environment already linked in publish-only mode, without requiring a managed tunnel. The CLI explicitly describes --publish-only as publishing agent activity with no managed tunnel, with Tailscale as an example of out-of-band access.

Actual behavior

The app shows a dialog titled “Live Activities unavailable”:

“Could not obtain environment link proof: Invalid managed endpoint origin.”

Live Activity Updates remains off, despite the environment link being provisioned and agent activity publishing enabled.

Impact

Minor bug or occasional failure

Version or commit

Server/CLI: t3 v0.1.7; iOS app: 2.2.0

Environment

iPhone with T3 Code mobile 2.2.0; environment accessed over Tailscale. Host CLI: t3 v0.1.7. Publish-only Connect link; no managed tunnel requested. Exact iOS version not recorded.

Logs or stack traces

t3 connect status

T3 Connect
  Exposure: enabled
  Authorization: stored credential
  Environment link: provisioned
  Relay: https://relay.t3.codes
  Publish agent activity: enabled
  Relay client: not installed

Screenshots, recordings, or supporting files

f92ffff5-ed20-4d72-92d5-f980d0b000af-3f9ed1b4-c8f3-45bc-af2e-a50a006f036d.jpg

Workaround

No verified workaround preserving the publish-only/Tailscale setup.

Possible cause (source inspection only; not confirmed against the installed app): enabling Live Activities calls linkEnvironmentToCloudWithPreference, which requests managedTunnelsEnabled: true and obtains a link proof through the saved connection URL. The server validates loopback origins for this proof. This may explain the origin error over Tailscale instead of reusing the existing publish-only link.

Source references at 4b87a45:

  • CLI:
    publishOnly: Flag.Boolean("publish-only").pipe(
    Flag.withDescription(
    "Link to publish agent activity only, with no managed tunnel. Reach this environment out of band (e.g. Tailscale).",
    ),
  • Mobile preference update: https://github.com/pingdotgg/t3code/blob/4b87a45770d24a47f7e6bc40e3f19011e41c7724/apps/mobile/src/features/agent-awareness/liveActivityPreferences.ts
  • Mobile linking:
    const challenge = yield* relayClient
    .createEnvironmentLinkChallenge({
    clerkToken: input.clerkToken,
    payload: {
    notificationsEnabled: true,
    liveActivitiesEnabled,
    managedTunnelsEnabled: true,
    },
    })
    .pipe(
    Effect.mapError(
    decodedRelayClientError(`${relayUrl}/v1/client/environment-link-challenges failed`),
    ),
    );
    const environmentClient = yield* makeEnvironmentHttpApiClient(input.connection.httpBaseUrl);
    const proof = yield* environmentClient.connect
    .linkProof({
    headers: { authorization: `Bearer ${localBearerToken}` },
    payload: {
    challenge: challenge.challenge,
    relayIssuer: relayUrl,
    endpoint: {
    httpBaseUrl: input.connection.httpBaseUrl,
    wsBaseUrl: input.connection.wsBaseUrl,
    providerKind: MANAGED_ENDPOINT_PROVIDER_KIND,
    },
    origin: endpointOrigin(input.connection.httpBaseUrl),
    },
    })
    .pipe(Effect.mapError(cloudEnvironmentLinkError("Could not obtain environment link proof.")));
    const link = yield* relayClient
    .linkEnvironment({
    clerkToken: input.clerkToken,
    payload: {
    deviceId,
    proof,
    notificationsEnabled: true,
    liveActivitiesEnabled,
    managedTunnelsEnabled: true,
    },
    })
    .pipe(
  • Origin validation:
    export function isAllowedEndpointOrigin(input: {
    readonly origin: RelayManagedEndpointOrigin;
    readonly requestUrl: string;
    readonly allowNonLoopbackRequestHost?: boolean;
    }): boolean {
    if (!isLoopbackHostname(input.origin.localHttpHost)) {
    return false;
    }
    const url = new URL(input.requestUrl);
    if (!input.allowNonLoopbackRequestHost && !isLoopbackHostname(url.hostname)) {
    return false;
    }
    return input.origin.localHttpPort === endpointRequestPort(url);
    }
    export function isSupportedLinkProviderKind(request: RelayLinkProofRequest): boolean {

Activity

  1. added
    bugSomething is broken or behaving incorrectly.
    needs-triageIssue needs maintainer review and initial categorization.
    on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.needs-triageIssue needs maintainer review and initial categorization.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions