Conversation
Minting a Matrix login token is rate-limited to ~1/min per account (a hardcoded Synapse anti-abuse limit). A second `browse` within the window fell through to an opaque `429 M_LIMIT_EXCEEDED` error. - auth.ts: add `MatrixRateLimitError` carrying the server-reported `retry_after_ms`; `requestLoginToken` now throws it on a 429 / `M_LIMIT_EXCEEDED` instead of the generic failure. - browse.ts: surface a clear, actionable message naming the ~1/min limit and the wait. Auto-wait and retry once when the wait is short (<=5s); add `--wait` to block out a longer window (capped at 90s). Never fall back to a tokenless open — the CLI can't tell which account the browser holds, so it could land on the wrong one. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A reported wait beyond the 90s ceiling now errors immediately instead of sleeping a capped 90s into a still-open window, where the retry was guaranteed to hit the limit again. `--wait` with no reported wait now blocks a full ~1min window (was 5s, which usually landed inside the window and failed). The rate-limit message only suggests `--wait` when it would change the outcome. requestLoginToken falls back to the standard Retry-After header when the deprecated retry_after_ms body field is absent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cd0d995960
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let mintToken = async () => { | ||
| try { | ||
| return await requestLoginToken(pm.getStoredMatrixAuth(profileId)); | ||
| } catch (err) { | ||
| if (!(err instanceof MatrixAuthError)) { |
There was a problem hiding this comment.
Share the re-authentication budget across mint retries
When the stored token is rejected, the re-authenticated mint is rate-limited, and the post-wait mint is also rejected for authentication, the second call to mintToken() receives a fresh re-authentication allowance and prompts for credentials again. This breaks the existing once-only recovery behavior and can make users re-enter their password twice during one browse invocation; track whether re-authentication has already occurred across both mint attempts.
Useful? React with 👍 / 👎.
Background and Goal
Minting a Matrix login token for
boxel browseis rate-limited to about once per minute per account — a hardcoded Synapse anti-abuse limit that can't be raised. Runningbrowsetwice within that window fell through to an opaque error:This replaces that with a typed error and a clear, actionable message, plus an opt-in wait/retry.
What changed
auth.ts— newMatrixRateLimitErrorcarrying the server-reported wait;requestLoginTokenthrows it on a429/M_LIMIT_EXCEEDEDinstead of the generic failure. The wait comes from the body'sretry_after_ms(deprecated in Matrix v1.10 but still sent by Synapse), falling back to the standardRetry-Afterheader.browse.ts— on a rate limit, surface a message naming the ~1/min limit and the wait. Auto-wait and retry once when the reported wait is short (≤5s) so genuine back-to-back opens just work;--waitblocks out a longer window — the reported wait, or a full ~1min window when none is reported. A reported wait beyond 90s is pathological for a 1/min limit and errors immediately: sleeping less than the server asked guarantees the retry fails, so no time is burned waiting. The message suggests--waitonly when it would change the outcome.--print-urlgets the same handling (message to stderr, non-zero exit, no URL on stdout).Key decision
No tokenless "open anyway" fallback. The CLI can't read the browser's session or know which account it holds. Loading the host app without a fresh token would land the user signed-in only if the browser already has a live session for the same account — otherwise it silently switches to the wrong account or a login wall. Since that can't be verified, we never open on a rate limit; we either wait for a real token (correct account guaranteed) or surface the error. The existing
MatrixAuthErrorre-auth path is untouched — a 429 deliberately does not trigger re-auth (a fresh token hits the same per-account limit).Testing
packages/boxel-cliunit suite green (browse.test.ts: 46 tests). New cases cover the 429 with/withoutretry_after_ms, theRetry-Afterheader fallback, theM_LIMIT_EXCEEDEDclassification, short-wait auto-retry,--wait(reported wait, no-reported-wait fallback, over-the-ceiling fail-fast), a persistent limit after retry, a rate limit surfaced by the post-re-auth mint, and--print-url. Lint +tsc --noEmitclean.smoke.test.ts/deadline-ladder.test.tsfailures are unrelated (they require a builtdist/viapnpm build).🤖 Generated with Claude Code