Skip to content

[Bug]: Android manual pairing rejects formatted codes and can report a false timeout #4889

Open

Description

@LLBlumire

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 (not currently listed in the issue template's Area options)

Steps to reproduce

  1. Run a headless T3 server and expose it through Tailscale Serve HTTPS.
  2. Create a one-time pairing credential. The CLI emits an uppercase, unhyphenated 12-character value.
  3. In the official Android app, open Add Environment.
  4. Enter the reachable HTTPS backend in Host.
  5. Enter the credential in the hyphenated format suggested by the field placeholder (for example, XXXX-XXXX-XXXX).
  6. Tap Add environment.
  7. Retry with the raw unhyphenated code.
  8. As a control, paste the complete https://<host>/pair#token=<raw-token> URL into Host, leave Pairing code empty, and submit.

Expected behavior

The manual pairing-code path should work reliably.

Either:

  • normalize presentation separators/whitespace and case before exchange, or
  • show the exact server-generated format and clearly require it.

The surfaced error should also match the actual failed request.

Actual behavior

  • Hyphenated manual entry is sent verbatim and the server returns 401 auth_invalid.
  • A retry with raw code also failed during this reproduction.
  • The app subsequently reported a timeout after 10000ms, despite the corresponding server-side /oauth/token request returning 401 in approximately 2.7ms.
  • Pasting the complete pairing URL into Host with Pairing code empty succeeded immediately.

The backend and transport were independently verified: environment discovery returned 200, Tailscale connectivity was healthy, and a disposable server-generated credential exchanged successfully through the same public HTTPS /oauth/token endpoint.

Impact

Major degradation or frequent failure.

The advertised manual host + pairing-code flow is unreliable. QR/full-URL pairing remains a workaround.

Version or commit

  • Server: t3 v0.0.32-nightly.20260729.951
  • Mobile: official Android client installed from Google Play on 2026-07-29

Environment

  • Device: Pixel 9a
  • Client OS: Android
  • Server OS: Linux x64
  • Transport: Tailscale Serve HTTPS on port 443
  • Mobile HTTP user agent observed server-side: okhttp/4.9.2

Logs or stack traces

GET  /.well-known/t3/environment -> 200
POST /oauth/token                  -> 401 (about 2.7ms)
Mobile UI                          -> timed out after 10000ms

Control:
POST /oauth/token with a disposable server-generated credential through
the same Tailscale HTTPS endpoint -> 200

Secrets, pairing credentials, environment IDs, trace IDs, and Tailnet hostnames have been omitted.

Relevant source observation

The Android pairing field currently shows the placeholder abc-123-xyz, while buildPairingUrl() only applies .trim() to the code before putting it into the URL fragment. It does not remove presentation separators or normalize case.

Relevant files:

  • apps/mobile/src/features/connection/ConnectionsNewRouteScreen.tsx
  • apps/mobile/src/features/connection/pairing.ts

Workaround

Paste the complete server-generated /pair#token=... URL into the Host field, leave Pairing code empty, then add the environment. Scanning the server-generated QR code should follow the same successful path.

Activity

  1. maria-rcks commented on Oct 9, 2026

    @maria-rcks
    Collaborator

    Note

    This is an automated response from a bot acting on maria's behalf.
    This issue has had no activity since 2026-07-30.
    Is it still relevant on the current version? If so, your version and OS would help.

  2. mixinDennisBarzanoffMixin commented on Oct 16, 2026

    @mixinDennisBarzanoffMixin

    +1

  3. juliusmarminge commented on Oct 22, 2026

    @juliusmarminge
    Member

    Inspected current main at 89fe509232. The manual pairing helper still only trims the credential before putting it in the token fragment; the field placeholder is now “Pairing code”, so the old formatting hint has changed. The reported Android 401-to-timeout behavior has not been reproduced. Further investigation and a fix require review of pairing credential handling and the authorization request path, which are outside this automated triage run’s allowed fix scope. Leaving open for maintainer review; no fix PR created.

  4. juliusmarminge commented on Oct 22, 2026

    @juliusmarminge
    Member

    Existing work check: #22089 is open and explicitly addresses this issue’s letter-case problem only; separators and the false timeout remain outside its scope. #22910 addresses stale Code overriding a pasted URL on mobile, a different symptom. Scanned all 938 open issues and 1,382 open PRs; no duplicate issue or complete fix found. No competing PR created.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions