T3 Connect: linking a 4th environment fails with an opaque 403 — quota not surfaced anywhere (client swallows the response body)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
TL;DR — with 3 environments already linked to T3 Connect, linking a 4th fails: the server retries POST /v1/client/environment-links for 10 minutes and logs a bare 403. Nothing in the UI, the CLI, or t3 connect status indicates a limit. Proven to be a quota by a reversible swap.
Setup: macOS, one machine, one account. Four environments: the desktop app + three headless web instances (t3 start --base-dir ~/.t3-<slot> --port 3151x, one per Claude account slot). Client 0.0.33-nightly.20260807.1025 (also reproduced on 0.0.32).
Symptom: the 4th environment never provisions. Server log, once per boot, after ~10 min of retries:
WARN: Failed to reconcile T3 Connect desired link on startup
cause: EnvironmentHttpInternalServerError
message: 'T3 Connect relay request failed: HttpClientError: StatusCode: non 2xx status code (403 POST https://relay.t3.codes/v1/client/environment-links)'
t3 connect status says Environment link: pending server startup / Relay: not provisioned the whole time — no hint that a request was rejected, let alone why.
Proof it's a quota (reversible swap):
- env A fails to link (403), envs B, C, desktop are linked and healthy;
t3 connect unlink --base-dir <C>→ single restart of A → A provisions within seconds;t3 connect link --base-dir <C>+ restart → C now fails with the same 403.
The slot frees immediately on revoke and is taken by whichever environment links next.
Ruled out along the way (each a controlled retry): stale/expired OAuth token, identity keypair rotation, environment-id rotation, full connect logout + fresh OAuth, client version, restart races, and deleting a dead environment entry from the UI (that entry was not holding a slot — the three healthy ones were the cap).
Which layer denies: replaying the flow by hand shows the denial happens after proof validation — a deliberately malformed proof returns 400 {"code":"environment_link_proof_invalid","reason":"invalid_signature_or_scope"}, while the server's valid proof returns 403 with no body I could observe from the client.
Asks:
- What is the environment limit, and is it documented? If it's ~3 per account, please state it in the docs and show a counter (
N of M) in Settings → Connections. - Surface the reason. The client logs only the status code and retries for 10 minutes; please relay the response body (or map it to a user-visible message) and fail fast on a quota denial instead of retrying.
t3 connect statusshould reflect it — "pending server startup" is misleading when the last attempt was rejected.- Can the limit be raised for a multi-instance setup like this (one machine, several account-isolated instances)? Related: #5623 (environments all display as the hostname, so a multi-instance list is also hard to tell apart).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the POST /v1/client/environment-links flow and the t3 connect status, link, and unlink entry points, then inspect Settings → Connections. Reproduce the fourth-environment 403 and compare the client-visible status with the server response body. Done means quota denials are surfaced clearly, retries stop when appropriate, status reflects rejection, and the documented limit and counter are present.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, cli, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100