From afa8f0d6177ad7016b3311f1ce1531fec9466973 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 5 Aug 2025 19:19:36 -0700 Subject: [PATCH] fix: exit cleanly when ShutdownComplete is received (#1864) Previous to this PR, `ShutdownComplete` was not being handled correctly in `codex exec`, so it always ended up printing the following to stderr: ``` ERROR codex_exec: Error receiving event: InternalAgentDied ``` Because we were not breaking out of the loop for `ShutdownComplete`, inevitably `codex.next_event()` would get called again and `rx_event.recv()` would fail and the error would get mapped to `InternalAgentDied`: https://github.com/openai/codex/blob/ea7d3f27bdc1da61df979419515889f64f36c5ce/codex-rs/core/src/codex.rs#L190-L197 For reference, https://github.com/openai/codex/pull/1647 introduced the `ShutdownComplete` variant. --- codex-rs/exec/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index 288b6177..06df2aeb 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -216,10 +216,16 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option) -> any res = codex.next_event() => match res { Ok(event) => { debug!("Received event: {event:?}"); + + let is_shutdown_complete = matches!(event.msg, EventMsg::ShutdownComplete); if let Err(e) = tx.send(event) { error!("Error sending event: {e:?}"); break; } + if is_shutdown_complete { + info!("Received shutdown event, exiting event loop."); + break; + } }, Err(e) => { error!("Error receiving event: {e:?}");