BigPizzaV3/CodexPlusPlus · error · RuntimeError

app-server 已退出,退出码

Error message

app-server 已退出,退出码 {self.proc.returncode}

What it means

During _request's wait loop, if the messages queue stays empty for 0.5s the code polls the app-server process; if poll() shows it has terminated, this error reports the exit code. It means the subprocess crashed or exited mid-request, so the pending JSON-RPC call can never be answered.

Solutions

  1. Check the captured stdout/stderr reader logs for the app-server's crash output (bad config, missing binary, port conflicts).
  2. Verify the codex binary version supports the requested method/app-server protocol.
  3. Restart the app-server client and retry; add supervisor logic to respawn the process on unexpected exit.
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at tools/codex-wechat/codex_wechat.py:450 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/5424b3de5f39c02d. Report an issue: GitHub.

Appendix: source

Thrown at tools/codex-wechat/codex_wechat.py:450

    def _send(self, message: dict[str, Any]) -> None:
        if not self.proc or not self.proc.stdin:
            raise RuntimeError("app-server 未启动")
        self.proc.stdin.write(json.dumps(message, ensure_ascii=False) + "\n")
        self.proc.stdin.flush()

    def _request(self, method: str, params: Any, timeout: int | None = None) -> dict[str, Any]:
        req_id = self.next_id
        self.next_id += 1
        self._send({"id": req_id, "method": method, "params": params})

        deadline = time.time() + (timeout or self.cfg.codex.timeout_seconds)
        while time.time() < deadline:
            try:
                msg = self.messages.get(timeout=0.5)
            except queue.Empty:
                if self.proc and self.proc.poll() is not None:
                    raise RuntimeError(f"app-server 已退出,退出码 {self.proc.returncode}")
                continue
            if msg.get("id") == req_id:
                if "error" in msg:
                    raise RuntimeError(f"{method} 失败:{msg['error']}")
                return msg.get("result") or {}
            # 其它通知留给当前请求外的事件循环自然丢弃。
        raise TimeoutError(f"{method} 超时")

    def _ensure_thread(self, user_id: str) -> str:
        thread_id = self.threads.get(user_id)
        if thread_id:
            return thread_id

        params: dict[str, Any] = {
            "cwd": self.cfg.codex.workspace,
            "approvalPolicy": self.cfg.codex.approval_policy,
            "sandbox": self.cfg.codex.sandbox,
            "ephemeral": True,

View on GitHub (pinned to b1ed92e5e4)