FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

BUG: keys fail to repaint on screensaver resume — MediaPlayerThread submits to a shut-down ThreadPoolExecutor · Issue #624 · StreamController/StreamController · GitHub

BUG: keys fail to repaint on screensaver resume — MediaPlayerThread submits to a shut-down ThreadPoolExecutor #624

Description

Describe the bug

When the deck wakes from the screensaver, most keys come back blank, or with the wrong image and no background — only the few key-render tasks queued before shutdown paint, and those without their backgrounds. The key actions still work (pressing a blank key fires its binding), so only the rendering is broken; the page config and input handlers loaded fine.

The render thread pool has already been shut down, but the long-lived MediaPlayerThread keeps trying to submit render tasks to it on resume, raising:

RuntimeError: cannot schedule new futures after interpreter shutdown

The entire traceback is in core src/backend/DeckManagement/DeckController.py — there are no plugin frames in it (full traceback below), so this looks like a core resume-path bug, not a plugin. Related but distinct from #535 (that one segfaults after load_background; here the app survives and just leaves the deck un-repainted).

To Reproduce

  1. Start StreamController (Flatpak) with a Stream Deck connected.
  2. Let the screensaver activate (idle for the configured delay).
  3. Wake the display / dismiss the screensaver.
  4. Deck comes back mostly blank; keys are functional but not drawn.

Intermittent — happens on some wakes, not all (appears timing-related, matching the note in #535).

Expected behavior

On resume, all keys repaint with their correct icons and backgrounds.

Screenshots

Before (deck blank / wrong colors after resume):

After (fix-streamcontroller restart — all keys repaint correctly):

Additional context

Full traceback:

ERROR | src.backend.DeckManagement.DeckController:run:78 - An error has been caught in function 'run', process 'MainProcess', thread 'MediaPlayerThread':
Traceback (most recent call last):
  File "/usr/lib/python3.12/threading.py", line 1032, in _bootstrap
    self._bootstrap_inner()
  File "/usr/lib/python3.12/threading.py", line 1075, in _bootstrap_inner
    self.run()
  File "/app/bin/StreamController/src/backend/DeckManagement/DeckController.py", line 197, in run
    self.perform_media_player_tasks()
  File "/app/bin/StreamController/src/backend/DeckManagement/DeckController.py", line 308, in perform_media_player_tasks
    task.run()
  File "/app/bin/StreamController/src/backend/DeckManagement/DeckController.py", line 78, in run
    self._callable(*self.args, **self.kwargs)
  File "/app/bin/StreamController/src/backend/DeckManagement/DeckController.py", line 670, in load_all_inputs
    futures.append(executor.submit(self.load_input, controller_input, page, update))
  File "/usr/lib/python3.12/concurrent/futures/thread.py", line 173, in submit
    raise RuntimeError('cannot schedule new futures after '
RuntimeError: cannot schedule new futures after interpreter shutdown

Preceding log context (crash fires right after "Hiding screen saver"):

ScreenSaver:hide:126 - Hiding screen saver
DeckController:load_page:737 - Loading page Main on deck CL46I1A01110
DeckController:load_brightness:638 - 50
DeckController:load_background:610 - Loading background in thread: ...
DeckController:load_screensaver:648 - Loading screensaver in thread: ...
DeckController:load_page:768 - Loaded page Main on deck CL46I1A01110
DeckController:run:78 - An error has been caught ... thread 'MediaPlayerThread' ...

Root cause (hypothesis): MediaPlayerThread (a persistent daemon thread) calls load_all_inputs() on resume, which does executor.submit(...) on a ThreadPoolExecutor that was shut down during the screensaver/teardown and never recreated. Either the executor should be recreated before the resume repaint, or load_all_inputs should guard against submitting to a dead pool (and the media-player loop should stop enqueuing after teardown).

Possible data-loss amplifier: when this cascades to a full app crash, data/pages/Main.json can get truncated to 0 bytes. An empty file is still valid JSON, so the invalid-JSON auto-fallback to pages/backups/Main.json does not trigger — the app then loads an empty page and the deck stays permanently dark until the page file is restored by hand. Suggests page saves aren't atomic (no temp-file + rename); worth hardening separately, as it turns a transient render glitch into a lost layout.

Environment:

  • OS: CachyOS Linux (kernel 7.1.2-3-cachyos), Hyprland (Wayland)
  • StreamController: 1.5.0-beta.14 (Flatpak, system install), commit cf05ced6b1902e1c98a6dd9087b17ad0484825f16c704416dfaf07f2d838a506
  • Device: Elgato Stream Deck XL (USB 0fd9:006c)
  • Python (Flatpak runtime): 3.12

Related issues: #535 (segfault variant of resume crash), #526 (stabilize resume during transient HID errors), #565 / #567 (resume/startup fixes in the same area), #604 (beta.14 startup instability, same version).

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


    Back | FazBrowse Home | New Git URL