Repository navigation
[Bug]: Completion notifications never appear on Windows: 73-character notification tag exceeds the platform tag limit #12287
Description
Activity
Triage
Confirmed on current
main(2d8378b44) and on v0.0.42. This is a real Windows desktop/web notification bug, not a permission, focus, or Electron-upgrade issue. The report’s diagnosis matches the code.What happens
Background thread alerts go through
ThreadNotificationCoordinator(apps/web/src/components/ThreadNotificationCoordinator.tsx). When the window is unfocused it still plays sound and then constructs a rendererNotification:const notification = new Notification(title, { body: thread.title, tag: `${environmentId}:${thread.id}`, silent: true, });
Both IDs are UUIDs in production:
- Environment: persisted
crypto.randomUUIDv4inapps/server/src/environment/ServerEnvironment.ts(not the desktop bootstrap slot"primary"). - Thread:
newThreadId()→randomUUID()inapps/web/src/lib/utils.ts(36 characters with dashes).
So the tag is always
36 + 1 + 36 = 73characters. That is not specific to WSL; every Windows install that uses the server’s real environment id hits it.On Windows, Chromium silently drops renderer notifications when the tag (plus origin) exceeds a platform toast-id budget. The
Notificationconstructor still succeeds and noerrorevent fires. That is why the app-side effects still run:- Sound is played before
new Notification(...). - The red taskbar overlay is set in
onNotificationafter the constructor returns (setNotificationBadge→ desktopsetOverlayIcon). - The toast never appears and Action Center never gets a row (
LastNotificationAddedTimeforcom.t3tools.t3codedoes not move).
Desktop identity matches the report: Electron 44.1.0, scheme
t3code, hostapp(ElectronProtocol.ts), AppUserModelIDcom.t3tools.t3code. Existing tests lock the long composite tag (tag: "env-1:thread-1"inThreadNotificationCoordinator.test.tsx).Why
thread.idalone is not the preferred fixThe reporter verified a 36-character thread UUID delivers on
t3code://app. That origin is short. Two reasons not to ship that:- [Bug]: Windows 11 web notifications don’t work when tag length is greater than 34 electron/electron#40433 documented a 34-character Windows 11 limit. 36 is over that documented bound.
- The remaining budget shrinks with origin length (their 45-vs-47 boundary moved with a longer origin). The web client uses
https://app.t3.codes, which is longer thant3code://app, so 36 is tighter there.
electron/electron#42239 hashed Electron’s native toast id and was merged in 2024. It does not make 73-character renderer tags safe: still reproducible on Electron 44.1.0 with T3’s scheme/AUMID. Do not wait on an Electron upgrade.
The pending map is keyed by
notification.tagand is meant to be unique per environment + thread (see the “compares the environment as well as the thread” test). Keep that uniqueness; just stop sending the raw composite string to Windows.Not a duplicate
No open issue matches “Windows toast never appears / tag too long.” Related but different:
Issue Why different #12048 Mobile APNs/FCM grouping by environment/thread, not desktop rendererNotification.tag#11073 / #8637 Relay / iOS push, different stack #6652 Sidebar unread badge electron/electron#40433, #42239 Upstream context; still broken for this renderer tag Suggested fix
- Extract a stable helper, e.g.
threadNotificationTag(environmentId, threadId), and use it fornew Notification({ tag })and the pending map. - Keep env+thread uniqueness with a short digest of
`${environmentId}:${thread.id}`(16 hex is enough; 32 hex still fits). Do not send the raw 73-character string. - Assert the composed tag length is ≤ 32 (under the documented 34-character Electron bound and the origin-dependent budget). Existing tests that expect
tag: "env-1:thread-1"need to use the helper. - Leave sound, badge,
silent: true, and click-to-navigate as they are.
macOS and Linux are unaffected. Same coordinator also serves Chromium-on-Windows web, so the short tag fixes both surfaces.
No reliable user workaround for the toast itself. Sound + taskbar badge still fire; in-app toasts only appear when the window is focused.
Labels / next
- Type: bug (accepted). Small, localized web change + test.
- Labels:
bug,accepted,via-triage. - Next: land the short tag helper and the length assertion. No Electron or Windows-permission change required.
- Environment: persisted
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.acceptedfeature request acceptedfeature request acceptedvia-triageFiled through npx t3 triageFiled through npx t3 triage
on Sep 17, 2026 - added a commit that references this issue
on Oct 10, 2026
Environment
0.0.42stable (desktop, Windows install; verified fromresources/app.asarand the exe version)44.1.0(Chrome152.0.7977.65)26200.9457t3code://appnotifications-and-sound(inAppNotificationsEnabled: false)Summary
When a turn completes while the desktop window is minimized or unfocused, Windows never shows the toast. The app still plays the notification sound and sets the red dot on the taskbar icon, and the Action Center stays empty.
The cause is the notification
taglength. The coordinator builds (ThreadNotificationCoordinator.tsx:181):Both IDs are UUIDs, so the tag is 36 + 1 + 36 = 73 characters. On Windows, Chromium silently drops renderer notifications when the tag exceeds a platform limit, and the budget is shared with the origin, so the threshold varies per app and Electron version. The
Notificationconstructor still succeeds and noerrorevent fires, which is why the app-side effects (sound, taskbar badge) still happen while the toast never appears.Steps to reproduce
Expected
A Windows toast appears and lands in the Action Center.
Actual
Sound plays, the red dot appears on the taskbar icon, no toast, nothing in the Action Center, and
LastNotificationAddedTimeforcom.t3tools.t3codenever advances.Evidence
Reproduced with a minimal Electron
44.1.0app that mirrors T3's setup: schemet3codewith the sameregisterSchemesAsPrivilegedprivileges and hostapp, the same AppUserModelID (com.t3tools.t3code),silent: true, title "Thread completed", a real thread title as the body, and the window minimized. Checked two ways: the renderer'sshowevent and Windows' own notification database (wpndatabase.db).control1showfired, DB row)<threadId>alone<envUuidPrefix>:<threadId><envUuid>:<threadId>(the actual format)show, no DB row)Boundary measurement with a slightly longer origin (
repro-app://app): 46-character tags deliver, 47 and up are dropped. With T3's shorter origin (t3code://app), 45 delivers and 73 drops. The threshold moving with the origin matches Electron's behavior where the Windows toast tag is derived from a notification ID that includes the origin.On the affected machine, the Windows notification database has no row from the main window origin at all. Every T3 notification that ever arrived had a short tag (manual test notifications created from a preview pane). The app-side creation path is confirmed to run: the taskbar badge is only set after
new Notification(...)succeeds.Related: electron/electron#40433 ("Windows 11 web notifications don't work when tag length is greater than 34") and electron/electron#42239, an attempted fix that hashes the tag. Still reproducible on Electron 44.1.0.
Suggested fix
Keep the tag short:
thread.idalone (36 characters, thread IDs are already unique), or${environmentId}:${thread.id}(for example 16 hex characters)Both the 36 and 45 character variants above were verified to deliver. I would pick the 36-character one for margin, since the limit varies with the origin and Electron version. Per-thread replacement semantics are preserved either way. A unit test asserting the composed tag stays under, say, 32 characters would guard against regressions.
This also affects the web client in Chromium browsers on Windows, since it is the same tag and platform path. macOS and Linux are not affected.
I can share the full minimal repro app and the raw logs if useful.