Description
The TUI toast system (packages/opencode/src/cli/cmd/tui/ui/toast.tsx) has no rate limiting or deduplication. Each call to toast.show() immediately replaces the current toast and auto-dismisses after 5 seconds. When multiple errors fire in rapid succession, the user only sees the last one — earlier error messages are invisible because they're immediately overwritten.
This was discovered while investigating #758, where mimo -c hangs silently when no sessions exist. That bug is a missing toast; this issue is the inverse problem: toasts that exist but can't be seen because they're overwritten.
Why this matters beyond sandbox
File IO errors don't just matter in sandbox/jail environments. In Unix, everything is a file — filesystem permission errors, NFS failures, full disks, and read-only mounts all cause cascading IO failures. When the TUI silently swallows .catch(() => {}) on history, frecency, and stash writes, users in these environments get no signal that anything is wrong.
Current behavior
toast.show() in ui/toast.tsx:61-67:
show(options: ToastOptions) {
const { duration = 5000, ...currentToast } = options
setStore("currentToast", currentToast)
if (timeoutHandle) clearTimeout(timeoutHandle)
timeoutHandle = setTimeout(() => {
setStore("currentToast", null)
}, duration).unref()
},
- Each call clears the previous timeout and replaces the current toast
- No deduplication: the same error message can flash 20 times in a row
- No rate limiting: a burst of IO failures produces a rapid strobe of toasts
Proposed behavior
Add a toast suppressor with two controls:
- Max warns per message: Once a specific message has been shown N times (e.g., 3), suppress further occurrences for the rest of the session
- Minimum interval: Don't show the same message again until at least T seconds (e.g., 30s) have passed since the last showing
These can be combined: "show this message at most 3 times, and never more than once per 30 seconds."
This allows adding .catch() toasts to currently-silent error paths (file IO, permission replies, question replies) without creating a strobing wall of error messages in read-only environments.
Steps to reproduce
- Run
mimo in a directory where the .mimo/ data directory is on a read-only filesystem
- Observe: no error messages are shown (all file IO failures are silently swallowed)
- Hypothetically, if
.catch(() => toast.show(...)) were added to all file IO writes: toasts would flash rapidly and only the last would be visible
Expected behavior
- Each distinct error message should be shown to the user at least once
- Repeated identical errors should be suppressed after a configurable count
- The same message should not reappear more than once per configurable time interval
Related
Discovered while investigating #758 (TUI hangs on blank screen when mimo -c runs with no sessions). The audit that found the missing toast also found 40+ .catch(() => {}) calls across the TUI — many in user-initiated paths that should show feedback, but adding toasts to all of them requires deduplication first.
Operating System
Linux
Description
The TUI toast system (
packages/opencode/src/cli/cmd/tui/ui/toast.tsx) has no rate limiting or deduplication. Each call totoast.show()immediately replaces the current toast and auto-dismisses after 5 seconds. When multiple errors fire in rapid succession, the user only sees the last one — earlier error messages are invisible because they're immediately overwritten.This was discovered while investigating #758, where
mimo -changs silently when no sessions exist. That bug is a missing toast; this issue is the inverse problem: toasts that exist but can't be seen because they're overwritten.Why this matters beyond sandbox
File IO errors don't just matter in sandbox/jail environments. In Unix, everything is a file — filesystem permission errors, NFS failures, full disks, and read-only mounts all cause cascading IO failures. When the TUI silently swallows
.catch(() => {})on history, frecency, and stash writes, users in these environments get no signal that anything is wrong.Current behavior
toast.show()inui/toast.tsx:61-67:Proposed behavior
Add a toast suppressor with two controls:
These can be combined: "show this message at most 3 times, and never more than once per 30 seconds."
This allows adding
.catch()toasts to currently-silent error paths (file IO, permission replies, question replies) without creating a strobing wall of error messages in read-only environments.Steps to reproduce
mimoin a directory where the.mimo/data directory is on a read-only filesystem.catch(() => toast.show(...))were added to all file IO writes: toasts would flash rapidly and only the last would be visibleExpected behavior
Related
Discovered while investigating #758 (TUI hangs on blank screen when
mimo -cruns with no sessions). The audit that found the missing toast also found 40+.catch(() => {})calls across the TUI — many in user-initiated paths that should show feedback, but adding toasts to all of them requires deduplication first.Operating System
Linux