Repository navigation
[Bug]: Desktop app held a Chromium "Video Wake Lock" for 14 hours, so the Mac never turned off its display or locked #15343
Description
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:
- 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.
- The last display-on event in the power log is at 23:02:50.
- At 23:02:53 the T3 Code main process took a
NoDisplaySleepAssertionnamed "Video Wake Lock". - 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/.movlinks and GitHubuser-attachmentsvideos - the recording helper, which plays a captured
MediaStreamin 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
juliusmarminge commentedon Oct 3, 2026
Note
Grok responding on behalf of Julius.
Triage
Thanks for the
pmsettrace and the careful write-up, @reowens! This is a real bug on currentmain(5e35272fda) and onv0.0.44, and I didn't find a duplicate. As you suspected, the app never asks for this lock itself. There's nopowerSaveBlockerand nonavigator.wakeLock.requestin the tree. ANoDisplaySleepAssertionnamed"Video Wake Lock"is Chromium's own display-sleep lock for anHTMLVideoElement.Chromium holds that lock only while the element is actually playing, the document is running, and one of these is true:
A
MediaStreamskips 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:
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>inAttachmentFilePreviewwith no hidden-document pause. Playback that never reachesended(a long file, a live source, or a stalledplayingelement) holds the lock until quit. The message list isn't virtualized, so a started video stays mounted after you scroll past it.HostedBrowserWebviewparks a full-sizevisibility: visiblewebview 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 stayvisibility: visible(the Electron 43 blanking workaround, already inv0.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.
createRecordingCompositorplays 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. Thecoreaudiodpreventuseridledisplaysleepassertions 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 notificationAudioContextinthreadNotifications.tsis 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
playingthen 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-suspensionduring 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 isprevent-display-sleep.Likely fix area
MediaVideoPlayer(and the raw preview<video>) when it scrolls out of view, not only on unmount or a hidden document.Until then, quitting the app or locking with Control-Command-Q is the right workaround. A maintainer will decide on the fix direction.
juliusmarminge commentedon Oct 27, 2026
I tried this on
mainatdc84b0962ewith the desktop app's Electron (44.9.3) under Xvfb. A stuborg.freedesktop.ScreenSaverservice logged every display wake lock Chromium took. It receives the same"Video Wake Lock"name thatpmsetshows.What took the lock and held it: a playing
<video>in a page Chromium treats as visible. That included a muted 64px live stream, a 1pxopacity: 0live stream, and an integrated-browser page with a looping muted video that was parked behind the app UI atz-index: -1. Nothing showed on screen in that last case.What released it:
visibilitywas hidden or visible, ordisplay: none.What never took it: a detached
<video>like the recording helper's, and a video scrolled out of view.On current
mainI couldn't find a path that keeps a video playing for hours with nothing visible, so I can't tell which part of the app held it in your session. These would narrow it down:pmset -g assertions | grep -i "wake lock"shows it: which threads, panels and browser tabs are open, and does closing the browser tabs or the Device panel make the assertion go away?