Discord: after fixing a permission, /join keeps refusing for up to 2 min (cached snapshot, 'then try again' text) #251

Closed
opened 2026-10-05 02:31:57 -04:00 by logan · 1 comment
Owner

Found reviewing PR #249 (server-26#225 S3). Not fixed there: it is a cache/rate-limit trade-off, not a one-liner.

What happens: the permission check reads discord_rest.guild_snapshot, cached per (bot, server). A snapshot whose channel says denied is still a Discord ok snapshot, so it lives discord_access_ttl_seconds (120 s). The 409 missing_permissions text ends "…allow Speak, then try again." A customer who fixes the permission and runs /join again within ~2 min gets the same refusal, because nothing on the start path bypasses the cache.

Who is affected: Discord /join and nodes.py discord_join users. The web picker is fine once S4 ships: its Re-check calls voice-check?refresh=1, which refreshes the shared cache. The reconciler self-heals within 120 s.

Why the obvious fix is wrong: refreshing on every missing_permissions start also refreshes on every reconciler pass (30 s) for each stuck persistent stream — plan finding 4, a REST loop against Discord.

Options:

  1. On a missing_permissions refusal, re-check only the denied bots whose snapshot fetched_at is older than ~15 s, with refresh=True, once, then re-pick. Bounded, but still 3 GETs per denied bot per reconciler pass.
  2. Same as 1, but only for interactive starts (pass a flag from the bot/web/node routes; the reconciler never refreshes).
  3. Change the text to "then try again in a couple of minutes" (cheapest, worst UX).

Option 2 looks right. Code: app/internal/discord_streams.py _start_locked / _perm_check; text in _fix_text.

Found reviewing PR #249 (server-26#225 S3). Not fixed there: it is a cache/rate-limit trade-off, not a one-liner. **What happens:** the permission check reads `discord_rest.guild_snapshot`, cached per (bot, server). A snapshot whose channel says *denied* is still a Discord `ok` snapshot, so it lives `discord_access_ttl_seconds` (120 s). The 409 `missing_permissions` text ends "…allow Speak, then try again." A customer who fixes the permission and runs `/join` again within ~2 min gets the same refusal, because nothing on the start path bypasses the cache. **Who is affected:** Discord `/join` and `nodes.py` `discord_join` users. The web picker is fine once S4 ships: its Re-check calls `voice-check?refresh=1`, which refreshes the shared cache. The reconciler self-heals within 120 s. **Why the obvious fix is wrong:** refreshing on every `missing_permissions` start also refreshes on every reconciler pass (30 s) for each stuck persistent stream — plan finding 4, a REST loop against Discord. **Options:** 1. On a `missing_permissions` refusal, re-check only the denied bots whose snapshot `fetched_at` is older than ~15 s, with `refresh=True`, once, then re-pick. Bounded, but still 3 GETs per denied bot per reconciler pass. 2. Same as 1, but only for interactive starts (pass a flag from the bot/web/node routes; the reconciler never refreshes). 3. Change the text to "then try again in a couple of minutes" (cheapest, worst UX). Option 2 looks right. Code: `app/internal/discord_streams.py` `_start_locked` / `_perm_check`; text in `_fix_text`.
logan added the area/discord
kind
behavior-bug
priority
p2
type
bug
labels 2026-10-05 02:32:04 -04:00
Author
Owner

Fixed in PR #262 (#262), option 2. start_stream(interactive=True) re-reads a bot whose cached verdict is denied and at least 10 s old, once, before refusing. /join and the admin page (POST /discord/streams), the web picker and nodes.py discord_join pass it. The reconciler never does. This closes when the PR merges ("Fixes #251").

Fixed in PR #262 (https://git.vpn.cusano.net/logan/server-26/pulls/262), option 2. `start_stream(interactive=True)` re-reads a bot whose cached verdict is denied and at least 10 s old, once, before refusing. `/join` and the admin page (`POST /discord/streams`), the web picker and `nodes.py` `discord_join` pass it. The reconciler never does. This closes when the PR merges ("Fixes #251").
logan closed this issue 2026-10-05 03:01:08 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: logan/server-26#251