Skip to content

[F2] 11 web component handlers swallow client mutation errors (no toast/log) #476

@intendednull

Description

@intendednull

Audit finding from #474 (commit 958e1ec)

Severity: medium
Category: observability / ux
File: 11 sites across crates/web/src/components/
Obvious fix: yes

Description

#350 (GEN-07, closed via PR #443) fixed silent error-swallowing in crates/web/src/handlers.rs by introducing warn_and_toast / warn_and_toast_with helpers. Pattern landed cleanly there but was not propagated to component-internal handlers.

11 sites in crates/web/src/components/ still discard anyhow::Result<()> from client mutations w/ let _ = h.<method>().await:

crates/web/src/components/roles.rs:56            let _ = h.create_role(&name).await;
crates/web/src/components/roles.rs:207           let _ = h.set_permission(&rid, parsed, granted).await;
crates/web/src/components/roles.rs:246           let _ = h.assign_role(eid, &r).await;
crates/web/src/components/roles.rs:291           let _ = h.delete_role(&rid).await;
crates/web/src/components/settings.rs:58         let _ = h.set_server_display_name(&name).await;
crates/web/src/components/settings.rs:439        let _ = h.mutate_grove_mute(target).await;
crates/web/src/components/sync_queue_view.rs:80  let _ = h.retry_queue().await;
crates/web/src/components/channel_sidebar.rs:191 let _ = h.create_voice_channel(&name_owned).await;
crates/web/src/components/channel_sidebar.rs:194 let _ = h.create_channel(&name_owned).await;
crates/web/src/components/channel_sidebar.rs:662 let _ = h.delete_channel(&name).await;
crates/web/src/components/channel_sidebar.rs:978 let _ = h.mutate_channel_mute(&channel, target).await;

All are direct user actions: create/delete role, grant/revoke permission, assign role, set display name, mute grove/channel, retry sync queue, create/delete channel. Action fails → user sees nothing. Same UX bug class as #350.

Note: at least one of these (roles.rs:207 set_permission swallow) was added/touched in the typed-Permission rework window; the warn_and_toast pattern was never propagated outside handlers.rs.

Impact / Threat

User-facing — silent failures across server-management surfaces (roles, channels, settings, queue retry). Users can't tell whether action took effect, especially under flaky network. Identical UX to bug #350 fixed; this is the un-migrated tail.

Developer-facing — no tracing::warn! either, so failures invisible in field logs.

Suggested fix

Mechanical migration. Each site can use the existing helpers from handlers.rs:

// before
let _ = h.create_role(&name).await;

// after
if let Err(e) = h.create_role(&name).await {
    crate::handlers::warn_and_toast_with("create role", &e, toasts.as_ref());
}

Pattern from handlers.rs (post-#350): capture let toasts = use_context::<ToastStack>(); on outer reactive frame before spawn_local, pass into warn_and_toast_with inside async body. wasm_bindgen_futures::spawn_local strips reactive owner, so naked use_context inside async block returns None.

Verify

rg -n "let _ = h\.[a-z_]+\(.*\)\.await" crates/web/src/components/ | wc -l
# 11

# After fix, expect: 0

Cross-ref

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions