Skip to content

[Bug][macOS][Dashboard] Stop button can unload launchd service before native Codex teardown completes #4023

Description

@tommy1616

Client or integration

OpenCodex dashboard with Codex Desktop.

Area

Dashboard / service lifecycle / Codex config restore.

Summary

On macOS with the launchd background service installed, pressing the dashboard Stop proxy button stopped the proxy and made the dashboard unreachable, but left Codex routed to http://127.0.0.1:10100/v1. Codex then could not send requests until the proxy was manually started again.

The current POST /api/stop control flow appears vulnerable to terminating its own process before shared teardown completes:

  1. stopServiceIfInstalledDetailed() is called.
  2. On macOS it synchronously invokes launchctl unload for the LaunchAgent.
  3. Only after that returns does the handler await performStopTeardown(), which calls the native Codex restore path.

Because the API handler runs inside the launchd-managed proxy process, unloading its own job can terminate it before step 3 finishes. This matches the observed state: the listener and dashboard were gone, while openai_base_url, experimental_realtime_ws_base_url, and model_catalog_json remained injected in the Codex config.

This ordering is still present in tag v2.48.0 at src/server/management-api.ts around lines 275-348 and src/service.ts around lines 2351 and 3927-3932.

Expected: dashboard Stop must restore native Codex and verify the restore before allowing launchd to terminate the proxy, or delegate the complete stop to an external process that survives unloading the service. If safe completion cannot be guaranteed, the dashboard should refuse and instruct the user to run ocx stop, similar to the existing Task Scheduler protection.

Reproduction

  1. On macOS, install and run OpenCodex as a launchd background service.
  2. Confirm Codex routing is injected and the dashboard is available on port 10100.
  3. Press Stop proxy in the dashboard and confirm.
  4. Observe that the proxy and dashboard stop.
  5. Inspect the effective Codex config.toml.
  6. Observe that the loopback routing keys may remain, leaving Codex pointed to the stopped proxy.
  7. Start the proxy again; Codex requests work again because the stale route becomes reachable.

Version

Observed on 2.42.0. Source ordering verified unchanged in tag 2.48.0.

Operating system

macOS, Apple Silicon, launchd user service.

Provider and model

Not provider-specific.

Logs or error output

After manually starting the proxy again, the service log reported that the previous session did not shut down cleanly and restored Codex state from the journal. There was no successful native-restore message associated with the dashboard stop.

Screenshots and supporting files

Relevant source:

Related but not duplicate:

Redacted configuration

openai_base_url = "http://127.0.0.1:10100/v1"
experimental_realtime_ws_base_url = "http://127.0.0.1:10100/v1"
model_catalog_json = "/redacted/.codex/opencodex-catalog.json"

Checks

  • I searched existing open and closed issues.
  • I removed secrets, tokens, account details, credentials, and personal paths.

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

    bugSomething isn't workingguiDashboard, tray, settings UIplatformOS/service/tray/ACL (Windows-heavy, not Windows-only)serviceService lifecycle (WinSW/launchd/scheduler)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions