Skip to content

[Bug]: Desktop app held a Chromium "Video Wake Lock" for 14 hours, so the Mac never turned off its display or locked #15343

Description

@reowens

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Impact

Major degradation or frequent failure

Version or commit

0.0.44

Environment

macOS 26.7 (arm64), T3 Code (Alpha) desktop app 0.0.44

Steps to reproduce

I don't have a deterministic repro yet. What happened:

  1. T3 Code was open on a Mac set to start the screen saver after 10 minutes, require a password immediately, and turn the display off after 20 minutes.
  2. The last display-on event in the power log is at 23:02:50.
  3. At 23:02:53 the T3 Code main process took a NoDisplaySleepAssertion named "Video Wake Lock".
  4. The display stayed on and unlocked until I quit T3 Code at 13:18:44 the next day. The assertion was released at the same second.

About 15 minutes earlier (22:48:13 and 22:48:19), T3 Code took the same assertion twice and released it within a second each time.

Expected behavior

An idle desktop app should not keep the display awake. If nothing visible is playing, the screen saver, display sleep and the lock screen should work normally.

Actual behavior

The display stayed on and the Mac stayed unlocked for 14 hours 15 minutes. pmset -g showed displaysleep 20 (display sleep prevented by T3 Code (Alpha)). No video was playing anywhere I could see in the app, and it made no sound.

"Video Wake Lock" is the name Chromium uses for the wake lock it takes on its own while a <video> element plays, so I don't think T3 Code asks for this directly. I found no powerSaveBlocker call or navigator.wakeLock.request in app.asar. These parts of the bundle can play video:

  • the chat renderer, which embeds .mp4/.webm/.mov links and GitHub user-attachments videos
  • the recording helper, which plays a captured MediaStream in a muted <video> it creates in script and doesn't add to the page (a.srcObject = e; ... await a.play())
  • the integrated browser

If one of these keeps playing after it scrolls offscreen, after its view closes, or after a recording ends without dispose(), Chromium would hold the lock for as long as the element exists.

Separately, coreaudiod released 42 per-client assertions 2 seconds after T3 Code quit: 21 contexts, each with a com.apple.audio.context<N>.preventuseridlesleep and a .preventuseridledisplaysleep, some held for 17 hours. The display still turned off at 21:51 and 22:59 while some of them were open, so they didn't keep it awake. I can't tie them to a specific part of the app. The completion sound creates one shared AudioContext and resumes it, and I didn't find a close() for it.

Logs

From pmset -g log:

2026-10-02 22:48:13 -0700 Assertions  PID 87583(T3 Code (Alpha)) Created NoDisplaySleepAssertion "Video Wake Lock" 00:00:00
2026-10-02 22:48:13 -0700 Assertions  PID 87583(T3 Code (Alpha)) Released NoDisplaySleepAssertion "Video Wake Lock" 00:00:00
2026-10-02 22:48:19 -0700 Assertions  PID 87583(T3 Code (Alpha)) Created NoDisplaySleepAssertion "Video Wake Lock" 00:00:00
2026-10-02 22:48:19 -0700 Assertions  PID 87583(T3 Code (Alpha)) Released NoDisplaySleepAssertion "Video Wake Lock" 00:00:00
2026-10-02 23:02:50 -0700 Notification  Display is turned on
2026-10-02 23:02:53 -0700 Assertions  PID 87583(T3 Code (Alpha)) Created NoDisplaySleepAssertion "Video Wake Lock" 00:00:00
2026-10-03 13:18:44 -0700 Assertions  PID 87583(T3 Code (Alpha)) Released NoDisplaySleepAssertion "Video Wake Lock" 14:15:51
2026-10-03 13:18:46 -0700 Assertions  PID 458(coreaudiod) Released PreventUserIdleDisplaySleep "com.apple.audio.context12620.preventuseridledisplaysleep" 14:30:32

From pmset -g assertions while it was held:

pid 87583(T3 Code (Alpha)): [0x0008997b00058fa5] 14:15:10 NoDisplaySleepAssertion named: "Video Wake Lock"

Workaround

Quit T3 Code before leaving the machine, or lock the screen manually (Control-Command-Q). To check whether it's happening, run pmset -g assertions | grep -i "wake lock".

Why this matters

A lock screen policy is a security control. On a shared office or a company Mac with a required auto-lock, an app that silently keeps the display awake leaves the machine unlocked. Issue #663 asked for keep-awake during agent runs and specified prevent-app-suspension so that the display can still sleep and auto-lock isn't affected. This bug breaks the same guarantee through Chromium's video wake lock.

Activity

  1. juliusmarminge commented on Oct 3, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks for the pmset trace and the careful write-up, @reowens! This is a real bug on current main (5e35272fda) and on v0.0.44, and I didn't find a duplicate. As you suspected, the app never asks for this lock itself. There's no powerSaveBlocker and no navigator.wakeLock.request in the tree. A NoDisplaySleepAssertion named "Video Wake Lock" is Chromium's own display-sleep lock for an HTMLVideoElement.

    Chromium holds that lock only while the element is actually playing, the document is running, and one of these is true:

    • the element is in picture-in-picture, or
    • the page is visible and the video is audible (it has an audio track with volume above 0), or
    • the page is visible and the video is both mostly on screen (about 75%) and large (about 20% of the viewport).

    A MediaStream skips the size check but still has to be visible or audible. The lock drops when those conditions stop being true. In your log it dropped in the same second the process quit, so the element stayed alive until then.

    Where it can come from

    Two parts of the app can do this without an obvious video on screen:

    • Chat, pull-request, and file videos go through MediaVideoPlayer (apps/web/src/components/media/MediaVideoPlayer.tsx). It pauses on unmount and when the document is hidden, including fullscreen, but not when the video scrolls out of view. An unmuted clip with an audio track keeps the lock while the window is visible, even after it scrolls away, until it ends, pauses, or unmounts. Inline chat videos aren't muted and can be up to 30rem, which is big enough to qualify while on screen. File previews also have a raw <video controls> in AttachmentFilePreview with no hidden-document pause. Playback that never reaches ended (a long file, a live source, or a stalled playing element) holds the lock until quit. The message list isn't virtualized, so a started video stays mounted after you scroll past it.
    • Integrated-browser guests can hold it while they're composited inside the window. A tab that's showing does, and so does a tab that recording, preview automation, or picture-in-picture marks as rendering-active. In that case HostedBrowserWebview parks a full-size visibility: visible webview at the top-left of the window, behind the UI (z-index: -1), so Electron keeps compositing it. A playing video in that guest then satisfies Chromium even while you're looking at chat. On macOS, inactive tabs also stay visibility: visible (the Electron 43 blanking workaround, already in v0.0.44), but they're placed fully outside the window and Electron stops compositing them, so that path shouldn't hold the lock unless something marks the tab rendering-active.

    Less likely sources

    The recording compositor is a weak fit. createRecordingCompositor plays a muted <video> that's never inserted into the document, and only when key or mouse decoration is on. Muted and not intersecting, it shouldn't qualify. The coreaudiod preventuseridledisplaysleep assertions are a separate mechanism: your log shows the display turning off while some were held, and they were released two seconds after quit, after the video lock. The shared notification AudioContext in threadNotifications.ts is never closed, but that isn't what kept the display on.

    Reading the timeline

    The sub-second locks at 22:48:13 and 22:48:19 fit a video that qualified and then paused or left view within the same second. The 14h 15m lock started at 23:02:53, three seconds after the display turned on, and lasted until exit, so something entered playing then and never paused. The log can't tell us whether that was a chat or file video or a browser guest, but it does rule out an app-level sleep blocker.

    This also isn't the same as #663. That request was about prevent-app-suspension during an active turn, so the display can still sleep and lock. This bug breaks that expectation from the other direction, because Chromium's video lock is prevent-display-sleep.

    Likely fix area

    • One option is to pause MediaVideoPlayer (and the raw preview <video>) when it scrolls out of view, not only on unmount or a hidden document.
    • Another is to check what a rendering-active browser guest can play while it's parked behind the UI.

    Until then, quitting the app or locking with Control-Command-Q is the right workaround. A maintainer will decide on the fix direction.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 3, 2026
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

    bugSomething 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