Skip to content

fix(web): suppress global error toast on mutations that own their toast UX#1397

Merged
MODSetter merged 1 commit into
MODSetter:devfrom
voidborne-d:fix/suppress-global-error-toast-mutations-dev
May 15, 2026
Merged

fix(web): suppress global error toast on mutations that own their toast UX#1397
MODSetter merged 1 commit into
MODSetter:devfrom
voidborne-d:fix/suppress-global-error-toast-mutations-dev

Conversation

@voidborne-d
Copy link
Copy Markdown
Contributor

@voidborne-d voidborne-d commented May 15, 2026

Closes #1371. Retarget of #1385 onto dev per @MODSetter's request (#1385 (comment)).

Summary

surfsense_web/lib/query-client/client.ts configures a global MutationCache.onError that calls showErrorToast(error) for every failed mutation unless mutation.meta?.suppressGlobalErrorToast is true. On dev (and main) the opt-out hook is defined in the consumer but has zero producers anywhere in the codebase — every mutation atom that already has its own onError: toast.error(...) was double-toasting on failure.

This PR activates the seam: it adds meta: { suppressGlobalErrorToast: true } to exactly the mutation atoms that own their own error toast, so the global handler skips them.

Files touched (9 atom files, 30 mutations)

File Mutations
atoms/prompts/prompts-mutation.atoms.ts 4
atoms/invites/invites-mutation.atoms.ts 4
atoms/chat-comments/comments-mutation.atoms.ts 4
atoms/new-llm-config/new-llm-config-mutation.atoms.ts 4
atoms/members/members-mutation.atoms.ts 3
atoms/roles/roles-mutation.atoms.ts 3
atoms/image-gen-config/image-gen-config-mutation.atoms.ts 3
atoms/vision-llm-config/vision-llm-config-mutation.atoms.ts 3
atoms/public-chat-snapshots/public-chat-snapshots-mutation.atoms.ts 2

Total: +30/-0 across 9 files.

Atoms intentionally left alone

These mutation atoms don't have their own onError toast and continue to rely on the global handler — touching them would invert their UX:

  • atoms/auth/auth-mutation.atoms.ts
  • atoms/user/user-mutation.atoms.ts
  • atoms/search-spaces/search-space-mutation.atoms.ts
  • atoms/logs/log-mutation.atoms.ts
  • atoms/documents/document-mutation.atoms.ts
  • atoms/connectors/connector-mutation.atoms.ts

Why no TypeScript module augmentation

The issue mentioned augmentation might be needed via TanStack Query's Register.mutationMeta. In v5 (@tanstack/react-query@^5.90.7), meta is typed as Record<string, unknown> | undefined by default, so the producer side compiles cleanly today. The consumer (client.ts) already uses optional chaining (mutation.meta?.suppressGlobalErrorToast) which is safe against the unknown value type.

Adding the module augmentation would tighten the contract on both sides but isn't required for this fix to work. Happy to layer it in as a follow-up if maintainers prefer that.

Diff vs #1385

Identical patch (cherry-picked from 2a5dcf7 on main-based branch). Verified clean apply on dev HEAD eea2d68. No conflicts; the 9 atom files have not diverged between main and dev for this surface.

Local validation (on dev)

  • pnpm biome check on the 9 touched files: clean (0 diagnostics).
  • tsc --noEmit baseline: pre-existing errors are unrelated; none of the touched files contribute new errors.

Test plan

  • Open Settings → Prompts; block the network in DevTools; attempt to create a prompt.
  • Verify exactly one error toast ("Failed to create prompt") appears, not two.
  • Repeat against any flow whose mutation lives in one of the 9 modified files (e.g. invite create, role create, comment create, vision-LLM-config update).
  • Verify success-path toasts in those flows are unchanged.
  • Verify atoms in the "left alone" set still get exactly one toast on failure (from the global handler).

🤖 Generated with Claude Code

High-level PR Summary

This PR fixes a double-toasting bug where mutation errors were displayed twice: once from the global error handler in client.ts and once from the mutation's own onError callback. The fix adds meta: { suppressGlobalErrorToast: true } to 30 mutations across 9 atom files that already handle their own error toasts, preventing the global handler from firing redundantly. Six other atom files that don't define custom error handlers are intentionally left unchanged to continue using the global toast mechanism.

⏱️ Estimated Review Time: 5-15 minutes

💡 Review Order Suggestion
Order File Path
1 surfsense_web/atoms/prompts/prompts-mutation.atoms.ts
2 surfsense_web/atoms/invites/invites-mutation.atoms.ts
3 surfsense_web/atoms/roles/roles-mutation.atoms.ts
4 surfsense_web/atoms/members/members-mutation.atoms.ts
5 surfsense_web/atoms/chat-comments/comments-mutation.atoms.ts
6 surfsense_web/atoms/public-chat-snapshots/public-chat-snapshots-mutation.atoms.ts
7 surfsense_web/atoms/new-llm-config/new-llm-config-mutation.atoms.ts
8 surfsense_web/atoms/vision-llm-config/vision-llm-config-mutation.atoms.ts
9 surfsense_web/atoms/image-gen-config/image-gen-config-mutation.atoms.ts

Need help? Join our Discord

…st UX

Closes MODSetter#1371. Retarget of MODSetter#1385 onto dev per maintainer request.

surfsense_web/lib/query-client/client.ts configures a global
MutationCache.onError that shows an error toast for every failed
mutation unless meta.suppressGlobalErrorToast is set. The opt-out
hook existed in the consumer but had zero producers — every mutation
atom that already had its own onError: toast.error(...) was
double-toasting on failure.

Add meta: { suppressGlobalErrorToast: true } to the 30 mutations
across 9 atom files that own their own error toast:

- atoms/prompts/prompts-mutation.atoms.ts (4)
- atoms/invites/invites-mutation.atoms.ts (4)
- atoms/chat-comments/comments-mutation.atoms.ts (4)
- atoms/new-llm-config/new-llm-config-mutation.atoms.ts (4)
- atoms/members/members-mutation.atoms.ts (3)
- atoms/roles/roles-mutation.atoms.ts (3)
- atoms/image-gen-config/image-gen-config-mutation.atoms.ts (3)
- atoms/vision-llm-config/vision-llm-config-mutation.atoms.ts (3)
- atoms/public-chat-snapshots/public-chat-snapshots-mutation.atoms.ts (2)

Atoms intentionally left alone (no local onError, rely on global):
auth, user, search-spaces, logs, documents, connectors.

Local validation (against dev): pnpm biome check on the 9 touched
files is clean; tsc --noEmit shows no new errors in the touched files
(pre-existing errors elsewhere unrelated).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 15, 2026

@voidborne-d is attempting to deploy a commit to the Rohan Verma's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 448358d1-39d5-4eee-a68a-f07dc62877ba

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@MODSetter MODSetter merged commit 1afecc9 into MODSetter:dev May 15, 2026
1 of 3 checks passed
@voidborne-d
Copy link
Copy Markdown
Contributor Author

Thanks @MODSetter — clean apply on dev. Appreciate the fast turnaround on the retarget.

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.

2 participants