Persistent app-server and pid-update-loop disappear without restart, leaving stale daemon state on Linux

Open 💬 2 comments Opened Jul 25, 2026 by Nadr0j
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

Remote Linux host is running standalone Codex CLI/app-server 0.145.0

What subscription do you have?

Pro

What platform is your computer?

Linux 6.12.63+deb13-amd64 x86_64 unknown

What issue are you seeing?

Summary

A persistent remote-control app-server on a Linux host stopped unexpectedly and was not restarted. Both the app-server and its managed pid-update-loop were absent afterward, leaving a stale control socket and
updater PID file. The host consequently became inaccessible from the ChatGPT mobile app.

This may be related to #23954, which reports managed-daemon PID instability and unexpected app-server replacement. This case differs because both managed processes disappeared and persistent mode did not recover
either one.

## Environment

  • Remote host OS: Debian 13 (trixie)
  • Kernel: Linux 6.12.63+deb13-amd64 x86_64
  • Codex CLI/app-server: 0.145.0
  • Install method: standalone
  • Authentication: ChatGPT
  • Daemon mode: persistent
  • Remote Control: enabled
  • Remote client: ChatGPT mobile app

The daemon settings file still contained:

``json
{
"remoteControlEnabled": true
}
``

## Actual behavior

Remote Control had been working from my phone. Later, the Linux host appeared offline and could no longer be accessed remotely.

codex doctor reported:

```text
⚠ app-server background server socket is stale or unreachable

daemon state dir ~/.codex/app-server-daemon
settings ~/.codex/app-server-daemon/settings.json (file)
pid file ~/.codex/app-server-daemon/app-server.pid (missing)
update-loop pid file ~/.codex/app-server-daemon/app-server-updater.pid (file)
control socket ~/.codex/app-server-control/app-server-control.sock
status stale or unreachable
app-server version unavailable (failed to connect to control socket)
mode persistent
```

Running the daemon version check produced:

``console
$ codex app-server daemon version
Error: failed to connect to /home/<redacted>/.codex/app-server-control/app-server-control.sock
``

No codex app-server or codex app-server daemon pid-update-loop process remained.

The stale updater PID file contained a PID that no longer existed:

``json
{
"pid": 2167423,
"processStartTime": "Fri Jul 24 15:35:29 2026"
}
``

The app-server stderr log ended abruptly at approximately 2026-07-24 20:55 PDT. It did not contain a panic, fatal application error, graceful shutdown, exit status, or terminating signal.

## Host investigation

I checked the host for an external termination cause:

```console
$ sudo journalctl --since "2026-07-24 20:45" \
--until "2026-07-24 21:10" |
grep -Ei 'oom|out of memory|killed process|codex|2167423|session|scope'

# No output
```

I also queried journald for the stale updater PID:

``console
$ sudo journalctl _PID=2167423 --no-pager
-- No entries --
``

Additional findings:

  • The host did not reboot.
  • There was no logged OOM-killer event.
  • There was no relevant systemd or session shutdown event.
  • There was no core dump.
  • No Codex update was installed at the failure time.
  • Codex state and log database integrity checks passed.
  • The final stderr entries were recoverable tool or model-cache errors, not a panic.

Because neither Codex nor journald retained a termination record, the original exit trigger cannot be determined retrospectively.

What steps can reproduce the bug?

Reproduction

I do not yet have a deterministic trigger:

  1. Install standalone Codex on a Linux host.
  2. Enable Remote Control and persistent daemon mode.
  3. Confirm the host is accessible from ChatGPT mobile.
  4. Leave the app-server running during normal Codex activity.
  5. Eventually, the mobile host becomes unavailable.
  6. Observe that both managed processes are absent while the socket and updater PID file remain stale.

I can provide a redacted codex doctor --json report and the daemon stderr log if needed.

What is the expected behavior?

Expected behavior

When persistent mode and Remote Control are enabled:

  1. The managed updater loop should remain alive.
  2. If app-server exits, it should be restarted automatically.
  3. If the updater loop also exits, another supervision mechanism should recover it.
  4. Exit status, terminating signal, and restart failures should be persisted.
  5. Stale sockets and PID files should be detected and repaired automatically.

The host should not remain offline indefinitely with stale daemon state.

Additional information

_No response_

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #35237

Powered by Codex Action

TusanHomichi · 2 days ago

I now have a deterministic reboot reproduction on standalone Codex CLI 0.149.1.

Environment:

  • Ubuntu 26.04.1 LTS, kernel 7.0.0-30-generic, x86_64
  • standalone Codex CLI/app-server 0.149.1
  • pid-managed app-server with Remote Control enabled
  • lingering systemd user manager invokes codex app-server daemon bootstrap --remote-control at boot

Before reboot, both managed processes were healthy. Their PID records persisted in ~/.codex/app-server-daemon/. After reboot, neither process existed, but bootstrap failed instead of classifying the previous-boot records as stale:

Error: failed to read start time for pid-managed app server 1902

The stale record was:

{"pid":1902,"processStartTime":"Wed Aug 26 10:25:14 2026"}

The user service consequently remained failed and Remote Control stayed offline. The same stale state also makes the supported recovery commands fail:

$ codex app-server daemon stop
Error: failed to read start time for pid-managed app server 1902

$ codex remote-control start --json
Error: failed to read start time for pid-managed app server 1924

Removing only the PID records whose process is absent (or whose live process start time differs from processStartTime) allows daemon bootstrap --remote-control to recreate both processes immediately. Both then report 0.149.1 and Remote Control connects.

Expected behavior: every daemon subcommand that reads a PID record should treat an absent PID or a start-time mismatch as stale state, remove/reconcile that record under the daemon lock, and continue. Malformed records should still fail loudly. This should make boot recovery deterministic without an external preflight.