AprilNEA/OpenLogi · error

failed to start GNOME stop helper

Error message

failed to start GNOME stop helper: {error}

What it means

Panic at source-spawn time in GnomeShellSource::observe: the dedicated 'openlogi-frontmost-gnome-stop' helper thread — which watches the StopToken and closes the worker's zbus Connection so the blocking observe loop wakes and can be joined — could not be spawned by the OS (thread::Builder::spawn returned Err, typically resource exhaustion or a pthread_create failure). The panic fires before the observe loop starts, so teardown of this frontmost source can never work; it is surfaced by unwrapping spawn's Result.

Solutions

  1. Check process/thread limits (ulimit -u, cgroup pids.max) and free memory on the host — spawn failures are almost always resource exhaustion
  2. Restart the openlogi-agent process to reclaim leaked threads or memory
  3. If it recurs on an embedded/limited host, consider reusing a shared stopper thread instead of spawning one per source
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at crates/openlogi-hook/src/linux/gnome_shell.rs:209 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13). Data as JSON: /api/errors/75118d1c94b9b931. Report an issue: GitHub.

Appendix: source

Thrown at crates/openlogi-hook/src/linux/gnome_shell.rs:209

        publish: PublishAppId,
    ) -> Box<dyn FrontmostSource> {
        // zbus owns its socket reader internally. A helper closes the worker's
        // current connection when teardown is requested, waking both streams
        // so the owning worker can synchronously return and join.
        let active_connection = Arc::new(Mutex::new(None::<Connection>));
        let stop_state = stop.state();
        let connection_to_close = Arc::clone(&active_connection);
        let stopper = thread::Builder::new()
            .name("openlogi-frontmost-gnome-stop".into())
            .spawn(move || {
                stop_state.wait();
                if let Some(conn) = lock_unpoisoned(&connection_to_close).take()
                    && let Err(error) = conn.close()
                {
                    debug!("gnome-shell: failed to close observer connection: {error}");
                }
            })
            .unwrap_or_else(|error| panic!("failed to start GNOME stop helper: {error}"));

        loop {
            if stop.is_requested() {
                break;
            }
            if self.conn.is_none() {
                self.conn = Self::connect_bus();
            }
            let Some(conn) = self.conn.as_ref() else {
                publish(None);
                if stop.wait_timeout(RECONNECT_DELAY) {
                    break;
                }
                continue;
            };
            *lock_unpoisoned(&active_connection) = Some(conn.clone());
            let outcome =
                futures_lite::future::block_on(Self::observe_connection(conn, &stop, &publish));

View on GitHub (pinned to e846e6f4b4)