Skip to content

fix(onboarding): don't fail first run when the relay forbids member channel creation - #15

Merged
mattbalza merged 1 commit into
mainfrom
fix/welcome-channel-owner-only-relay
Aug 5, 2026
Merged

fix(onboarding): don't fail first run when the relay forbids member channel creation#15
mattbalza merged 1 commit into
mainfrom
fix/welcome-channel-owner-only-relay

Conversation

@mattbalza

Copy link
Copy Markdown
Owner

Problem

A new teammate installed Buzz against buzz.scalarly.org and hit a red error on first run:

403 Forbiddenrestricted: only workspace owners may create durable channels or forums

That message is our relay working as configured (BUZZ_RELAY_CHANNEL_CREATE_POLICY=owner-only,
crates/buzz-relay/src/handlers/ingest.rs:2260). What's broken is the client's reaction to it.

Desktop's first run creates a personal, private "Welcome" channel per member. On an
owner-only relay that create is rejected for every non-owner, and:

  1. initializeStarterChannels already wraps ensureStarterChannels in try/catch, but
    ensureWelcomeChannel threw straight through to the outer catch → {ok: false}.
  2. CommunityOnboardingFlow.finalize() re-throws on !result.ok → "Couldn't set up
    starter channels", with "Take me to Buzz" only turning into "Skip for now" after two failures.
  3. markWelcomeChannelEnsured never ran, so the mount retry effect re-attempted the
    rejected create forever — visible in the relay log as a 403 roughly every 46s.

The member was fully provisioned and every shared channel was reachable. The only thing
missing was an optional personal room.

Fix

Treat the private Welcome channel as a nicety the community may not offer:

  • ensureOptionalWelcomeChannel (welcome.ts) resolves to
    {channel: null, unavailableReason} instead of rejecting.
  • initializeStarterChannels skips the query-cache seeding, seedWelcomeExperience,
    rememberPendingWelcomeChannel and notifyWelcomeChannelReady when there is no channel,
    and calls markWelcomeChannelEnsured so the retry effect stops re-attempting.
  • resolveWelcomeFocusChannelId lands first run on welcome-everyone, falling back to
    general, when there is no private Welcome channel.

Genuine starter-channel failures still return {ok: false} and surface exactly as before —
only the optional personal room is downgraded.

Test plan

  • desktop/src/features/onboarding/welcome.test.mjs — 5 new cases: success passthrough,
    the owner-only rejection (using the relay's verbatim message), a non-Error rejection,
    and both focus-fallback rungs. Written failing first, then made green.
  • Full desktop suite: 3884 passed / 0 failed.
  • pnpm exec tsc --noEmit, pnpm exec biome lint src/features/onboarding, pnpm build — clean.
  • Manual: fresh install against an owner-only relay reaches the app and lands in
    welcome-everyone with no error toast; against an owner/any-member relay the private
    Welcome channel is created and focused exactly as before.

…hannel creation

A relay running `channel_create_policy=owner-only` rejects the personal
private "Welcome" channel for every non-owner member with

    restricted: only workspace owners may create durable channels or forums

`initializeStarterChannels` already treated the public starter channels as
best-effort, but `ensureWelcomeChannel` threw straight through, so first run
returned `{ok: false}` and `CommunityOnboardingFlow.finalize()` re-threw it —
painting "Couldn't set up starter channels" on a brand-new install even though
the member was fully provisioned and every shared channel was reachable.

Treat the private Welcome room as optional:

- `ensureOptionalWelcomeChannel` resolves to `{channel: null, unavailableReason}`
  instead of rejecting.
- Skip the seeding, pending-channel and ready-event work when there is no
  channel, and mark the welcome channel as settled so the mount effect stops
  re-attempting the rejected create every ~46s.
- `resolveWelcomeFocusChannelId` lands first run on `welcome-everyone`, then
  `general`, when there is no private Welcome channel.

Genuine starter-channel failures still surface as before.

Signed-off-by: mattbalza <mattbalza@users.noreply.github.com>
@mattbalza
mattbalza merged commit d0a9788 into main Aug 5, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant