Repository navigation
[Bug]: Stable t3 pair prints an unusable token for a running Nightly/V2 server #15492
Description
Before submitting
- I searched existing issues and did not find a duplicate of this specific failure.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- Run T3 Desktop Nightly 0.0.46-nightly.20261004.2644 on macOS with its existing T3 home after V2 migration. The live environment descriptor reports orchestrationProtocolVersion: 2.
- On the same Mac, run npx t3 pair. In the observed setup this selected stable CLI 0.0.45. To keep the CLI version deterministic, use npx --yes t3@0.0.45 pair.
- Use the freshly generated pairing URL with the live server before the token expires. The command prints a QR, URL, token, and expiry as if pairing can succeed.
- The receiving client reports an invalid pairing token.
Expected behavior
The CLI should generate a credential usable by the discovered running server, or reject an incompatible server/CLI pairing before opening or writing a database. A channel/protocol mismatch should give an actionable explanation and a command using the matching server version.
Actual behavior
The stable CLI discovered the running Nightly server but issued its link in V1 state.sqlite. The running Nightly server used V2 statev2.sqlite and could not see that credential. The command appeared successful; the later invalid-token message did not identify the version/database mismatch.
Read-only database metadata checks located the stable command's new link in state.sqlite and showed no corresponding new link in statev2.sqlite. Issuing a replacement with the matching Nightly CLI created a link in statev2.sqlite and pairing succeeded. The existing HTTPS discovery endpoint continued to reach the intended protocol-2 server.
Impact
Major degradation: the default npx pairing command appears to work but cannot pair to an already-running V2 host. A matching-version command provides a workaround.
Version or commit
Pairing CLI: t3 0.0.45 (stable).
Running Mac desktop/server: 0.0.46-nightly.20261004.2644, orchestration protocol 2.
Working replacement CLI: 0.0.46-nightly.20261004.2644.
Observed October 4, 2026.
Environment
macOS T3 Desktop, existing user T3 home containing both V1 and V2 databases, CLI invoked via npx. Tailscale provided private HTTPS access. The owner confirmed successful Safari pairing and then native iPhone pairing after the workaround. No separate development worktree server was involved in this diagnosis. Exact macOS, Node, and iPhone build numbers were not captured.
Logs or stack traces
No stack trace was captured. Pairing URLs, credentials, hostnames, account identities, and network addresses are omitted.
Nonsecret metadata from the original stable link:
- state.sqlite: created_at 2026-10-04T04:49:08.849Z; expires_at 2026-10-04T04:54:08.849Z.
- statev2.sqlite: no corresponding new link at that time.
Replacement generated by the matching Nightly CLI: - statev2.sqlite: created_at 2026-10-04T04:54:00.561Z; expires_at 2026-10-04T05:09:00.561Z.
Workaround
Run on the machine hosting the already-running server:
npx --yes t3@0.0.46-nightly.20261004.2644 pair --tailscale --ttl 15m
Use the exact running server version for later setups. npx --yes t3@nightly pair --tailscale also worked when the nightly tag matched the installed server. Use a fresh token per receiving app/browser; opening it in Safari authorizes Safari separately from the native phone app.
Related context
#10516 is related to the pairing CLI opening an installed server's database using another runtime's schema, but concerns development-worktree migrations rather than stable/V2 tokens being written to different databases.
#10516
V2 migration documents separate state.sqlite / statev2.sqlite databases:
#14871
The observed Nightly pairing implementation discovers the running server and derives storage paths before issuing the token:
https://github.com/pingdotgg/t3code/blob/v0.0.46-nightly.20261004.2644/apps/server/src/cli/pair.ts
Activity
juliusmarminge commentedon Oct 4, 2026
Note
Grok responding on behalf of Julius.
Triage
Thanks for the really thorough report, @walterbarrera1234, especially the read-only database checks and the working command. This looks like a real pairing bug, and it isn't a duplicate of #10516 or #14871.
What I found
t3 pairfinds the running server throughuserdata/server-runtime.json, which V1 and V2 still share, but then writes the token to the CLI's own database. Onv0.0.45that'sstate.sqlite, and onv0.0.46-nightly.20261004.2644it'sstatev2.sqlite.apps/server/src/cli/pair.tsis the same on both versions and doesn't compare the discovered server'sorchestrationProtocolVersion(1 vs 2) orserverVersionwith its own before writing. So the stable CLI can print a valid-looking QR and URL for the Nightly server while the credential only exists in the V1 database.Your matching-version workaround (
npx --yes t3@<running server version> pair) is the right one for now.Likely fix area
t3 pairinapps/server/src/cli/pair.ts: one option is to check the discovered descriptor's protocol and server version before opening a database, and exit with the exact matchingnpx t3@<server version> paircommand when they differ.t3@0.0.45would keep behaving this way, there's also a question of whether the stable package needs a patch sonpx t3 pairfails clearly while a Nightly V2 server is running.A maintainer will decide on the fix direction.
juliusmarminge commentedon Oct 22, 2026
Fresh triage: this reports a pairing compatibility bug, not an exploitable vulnerability. No duplicate found in open issues from the last 90 days for stable/Nightly pairing, V1/V2 token storage, or “invalid pairing token”.
At 07d38b8d17, code inspection shows
pairCommanddiscovers the running server, derives local database paths, then callsEnvironmentAuth.createPairingLink. Addressing the reported mismatch touches pairing authentication/credential handling, so the automated triage hard stop requires maintainer handling. No runtime reproduction or code changes were made; leaving this open for Julius.juliusmarminge commentedon Oct 22, 2026
Reproduced on Linux with current main at 044f07257c:
t3@0.0.45 pairprinted a token for a protocol-2 server, which rejected the fresh credential with HTTP 401. The matching CLI succeeded. #23789 adds a protocol check before database access, with a matching-version command on rejection. The already-published 0.0.45 package remains affected.