AprilNEA / AprilNEA/OpenLogi

[Bug]: macOS: a removed launchd job strands the agent for good — kickstart loops on 113 while SMAppService still reports Enabled

Open
#1,302 1 comment 1 reaction 0 assignees View on GitHub
platform: macos type: bug
Dominant language
Rust
Stars
21k
Forks
675
Avg merge
2d 5h
Merged PRs (30d)
172

Description

**Component:** Agent / GUI (login-item registration)
**Version:** 0.8.3
**OS:** macOS 26.6.2 (25G83), arm64
**Area:** Menu bar / background agent, Settings / configuration (TOML)

## What happened

Something removed the agent's launchd job (`launchctl bootout` / `unload` — an
app cleaner, an uninstaller sweep, or a manual restart attempt). The agent
exited and never came back: not by kickstart, not after quitting and relaunching
the GUI, not after a fresh login. Every settings change then lands in
`config.toml` but is never applied, and the window shows the fail-closed notice
"saved, but the agent is not running, so it has not been applied yet". Its
primary button — "Relaunch OpenLogi" — restarts the *GUI*, so it changes
nothing about this state.

The GUI's own log shows the loop, once every `SPAWN_RETRY_PERIOD`:

```
WARN openlogi_desktop::services::ipc::launch: launchctl kickstart failed
target=gui/501/org.openlogi.agent.service status=exit status: 113
stderr=Could not find service "org.openlogi.agent.service" in domain for user gui: 501
WARN openlogi_desktop::services::ipc::launch: launchctl kickstart failed (second rung, after ensure_registered)
target=gui/501/org.openlogi.agent.service status=exit status: 113 ...
WARN openlogi_desktop::services::ipc::launch: agent is not running and the supervised
launch paths could not start it — leaving it down status=Enabled
```

## Root cause

`SMAppService` reads the Background Task Management record; `launchctl`
addresses the launchd domain. A `bootout` removes the job and leaves the
record, so the two disagree — and every recovery path in the GUI is keyed on
the record:

- `kickstart_registered_agent()` (`services/ipc/launch.rs`) sees
`status() == Enabled`, runs `launchctl kickstart`, and gets exit 113
("Could not find service"). It returns `false` — with no way to say *why*.
- The second rung calls `registration::ensure_registered()`. Its rule
(`platform/registration/macos.rs::ensure_action`) is `Enabled` + version
marker current ⇒ `None`: nothing to do. So nothing is done.
- Registering again would not help on its own either: on a surviving record
`SMAppService.register` returns `kSMErrorAlreadyRegistered` (which
`backend::register` forgives as success) without submitting a job. Only the
unregister-then-register dance that `EnsureAction::Reregister` already
performs rebuilds one.

So the state is self-sustaining: the record keeps the repair from running, and
without the repair the job never comes back. A reboot does not help — the
record is what login start reads.

Timeline from this machine (unified log + `~/.local/state/openlogi/agent.*.log`):

```
22:49:46.512 agent : releasing the input hook and exiting reason="shutdown signal"
22:49:46.557 launchd: [gui/501/org.openlogi.agent.service] caller removing service: caller = launchctl[89099]
22:49:46.599 launchd: [gui/501] removing service: org.openlogi.agent.service
23:09:31 → GUI : kickstart 113 / kickstart 113 / "leaving it down" status=Enabled, every 30 s
```

`launchctl print gui/501/org.openlogi.agent.service` → "Could not find service",
while `launchctl print-disabled gui/501` still lists the label as `enabled` and
`SMAppService` reports `Enabled`.

## Workaround

Force the re-registration dance the GUI declines to run, by making the version
marker read as stale:

```sh
rm ~/.local/share/openlogi/registration-version
# quit and relaunch OpenLogi
```

The next launch takes `ensure_action(Enabled, stale) → Reregister`, launchd gets
a job again, and the agent starts (verified on this machine — agent, hook, tray
and overlay all came back within seconds).

## Expected

`launchctl` answering "no such service" for a registration that reports
`Enabled` should rebuild the registration, not be retried forever.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in services/ipc/launch.rs with kickstart_registered_agent(), then trace platform/registration/macos.rs and ensure_action, including the existing EnsureAction::Reregister path. Reproduce the Enabled-but-missing-service state and make the recovery stop retrying exit 113 forever; verify that the launchd job and agent return without requiring a stale registration-version marker.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, rust
Domain
desktop, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.