Skip to content

[Bug]: Completion notifications never appear on Windows: 73-character notification tag exceeds the platform tag limit #12287

Description

@satyalyadav

Environment

  • T3 Code 0.0.42 stable (desktop, Windows install; verified from resources/app.asar and the exe version)
  • Electron 44.1.0 (Chrome 152.0.7977.65)
  • Windows 11 25H2, build 26200.9457
  • Backend in WSL2 (Ubuntu), client served to the desktop window via t3code://app
  • Notification mode notifications-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 tag length. The coordinator builds (ThreadNotificationCoordinator.tsx:181):

tag: `${environmentId}:${thread.id}`

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 Notification constructor still succeeds and no error event fires, which is why the app-side effects (sound, taskbar badge) still happen while the toast never appears.

Steps to reproduce

  1. Settings -> General -> Thread notifications: choose a mode that includes notifications.
  2. Minimize the T3 Code window (or focus another app).
  3. Send a message to an agent and let the turn finish.

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 LastNotificationAddedTime for com.t3tools.t3code never advances.

Evidence

Reproduced with a minimal Electron 44.1.0 app that mirrors T3's setup: scheme t3code with the same registerSchemesAsPrivileged privileges and host app, 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's show event and Windows' own notification database (wpndatabase.db).

tag length delivered
control1 8 yes (show fired, DB row)
<threadId> alone 36 yes
<envUuidPrefix>:<threadId> 45 yes
<envUuid>:<threadId> (the actual format) 73 no (no 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.id alone (36 characters, thread IDs are already unique), or
  • a short digest of ${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.

Activity

  1. juliusmarminge commented on Sep 17, 2026

    @juliusmarminge
    Member

    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 renderer Notification:

            const notification = new Notification(title, {
              body: thread.title,
              tag: `${environmentId}:${thread.id}`,
              silent: true,
            });

    Both IDs are UUIDs in production:

    • Environment: persisted crypto.randomUUIDv4 in apps/server/src/environment/ServerEnvironment.ts (not the desktop bootstrap slot "primary").
    • Thread: newThreadId() → randomUUID() in apps/web/src/lib/utils.ts (36 characters with dashes).

    So the tag is always 36 + 1 + 36 = 73 characters. 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 Notification constructor still succeeds and no error event fires. That is why the app-side effects still run:

    • Sound is played before new Notification(...).
    • The red taskbar overlay is set in onNotification after the constructor returns (setNotificationBadge → desktop setOverlayIcon).
    • The toast never appears and Action Center never gets a row (LastNotificationAddedTime for com.t3tools.t3code does not move).

    Desktop identity matches the report: Electron 44.1.0, scheme t3code, host app (ElectronProtocol.ts), AppUserModelID com.t3tools.t3code. Existing tests lock the long composite tag (tag: "env-1:thread-1" in ThreadNotificationCoordinator.test.tsx).

    Why thread.id alone is not the preferred fix

    The reporter verified a 36-character thread UUID delivers on t3code://app. That origin is short. Two reasons not to ship that:

    1. [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.
    2. 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 than t3code://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.tag and 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 renderer Notification.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

    1. Extract a stable helper, e.g. threadNotificationTag(environmentId, threadId), and use it for new Notification({ tag }) and the pending map.
    2. 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.
    3. 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.
    4. 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.
  2. added
    bugSomething is broken or behaving incorrectly.
    acceptedfeature request accepted
    via-triageFiled through npx t3 triage
    on Sep 17, 2026
  3. added a commit that references this issue on Oct 10, 2026
    13ebd25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions