fix(web): toast + log on handler failures#443
Merged
intendednull merged 1 commit intoApr 27, 2026
Conversation
Handler closures in `crates/web/src/handlers.rs` swallowed every async error with `let _ = h.<action>(...).await`. Send/edit/delete/react/ pin/unpin failures vanished — typed message disappeared from input, no log, no toast. Refs #350 [GEN-07]. New `warn_and_toast_with(action, e, toasts)` helper: - `tracing::warn!(error = ?e, action, "ui handler failed")` - Pushes `Toast::err("Couldn't {action}. Try again.")` with a per- action `dedup` key so back-to-back failures coalesce instead of stacking. Mirrors the lazy `use_context::<ToastStack>()` pattern PR #411 introduced for the inbound mark-read button. Each handler now captures the toast stack on the synchronous frame (reactive owner intact) before `spawn_local`, then forwards into the helper from the async path — `wasm_bindgen_futures::spawn_local` strips the owner, so context lookup must happen earlier. 7 sites patched: send_message, send_reply, edit_message, delete_ message, react, pin_message, unpin_message. switch_channel / switch_server stay as-is — they return `()` so there was nothing to swallow. Browser test `handler_error_toasts::*` covers helper happy-path, dedup coalescing, and missing-stack no-panic. Test exercises the exact production code path; the handler closures themselves are pinned to ClientHandle<IrohNetwork> with no trait seam to inject a failing double, so going one level deeper would buy nothing. `rg "let _ = h\." crates/web/src/handlers.rs` returns empty. fmt + clippy + native tests + wasm check all green; browser tier verified locally via `cargo check -p willow-web --tests` + manual review of the test mod (Firefox/wasm-pack not on this box, browser suite runs in CI).
This was referenced Apr 27, 2026
intendednull
added a commit
that referenced
this pull request
Apr 28, 2026
…480) PR #443 closed #350 by routing client-mutation errors in handlers.rs through warn_and_toast / warn_and_toast_with so the user sees a toast instead of the action silently vanishing. The pattern was not propagated to component-internal handlers — 11 sites across roles.rs, settings.rs, sync_queue_view.rs, and channel_sidebar.rs still discarded the anyhow::Result with `let _ = h.foo(...).await`. Migrate all 11 sites: - roles.rs: create role, set permission, assign role, delete role - settings.rs: set server display name, mute server - sync_queue_view.rs: retry queue - channel_sidebar.rs: create channel, create voice channel, delete channel, mute channel Each site now captures `let toasts = use_context::<ToastStack>()` on the outer reactive frame (before `wasm_bindgen_futures::spawn_local`, which strips the reactive owner), moves it into the async block, and dispatches `crate::handlers::warn_and_toast_with("<action>", &e, toasts.as_ref())` on Err. `rg -n 'let _ = h\.[a-z_]+\(.*\)\.await' crates/web/src/components/` goes from 11 hits to 0. Refs #476
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Handler closures in
crates/web/src/handlers.rsate every async errorvia
let _ = h.<action>(...).await. Typed message vanish from input,no log, no toast. Refs #350 [GEN-07].
New
warn_and_toast_with(action, e, toasts)helper:tracing::warn!(error = ?e, action, "ui handler failed")Toast::err("Couldn't {action}. Try again.")with per-actiondedupkey — back-to-back fail coalesce, no stack pile-up.use_context::<ToastStack>()pattern from PR fix(web): busy gate + toast on mark-read #411.Each handler grabs toast stack on synchronous frame (reactive owner
intact) before
spawn_local, then forwards into helper from asyncpath.
wasm_bindgen_futures::spawn_localstrip owner — context lookupmust happen earlier.
Sites patched (7)
send_messagesend_replyedit_messagedelete_messagereactpin_messageunpin_messageswitch_channel/switch_serverreturn()— nothing to swallow,left as-is.
Overlap with PR #411
PR #411 toast inbound mark-read fail in
sync_queue_view.rs. Differentfile, different action namespace (
mark as readvssend messageetc.),different dedup keys. No double-toast.
Verify
Empty.
Test plan
cargo fmt --checkcleancargo clippy --workspace --all-targets -- -D warningscleancargo check -p willow-web --target wasm32-unknown-unknowncleancargo test -p willow-web --lib72 passcargo test --workspace --exclude willow-weball greenhandler_error_toasts::*(3 cases: happy-path,dedup coalesce, no-stack no-panic) compile clean. Firefox +
wasm-pack not on this box — browser tier runs in CI.
Follow-ups
None.
switch_channel/switch_serverreturn(); if they grow afallible variant later, plumb same helper.
https://claude.ai/code/session_016cmtqT7yEQUgjcLgz4pARP
Generated by Claude Code