Python SDK: CodexClient.close() leaves the app-server's stdout/stderr pipes open (and never waits after kill)
I maintainer di solito rispondono entro 1 giorno
@akhil9tiet ci sta già lavorando.
Dal 17/10/2026.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 82/100
Direzione di ricerca
Inizia da CodexClient.close() in sdk/python/src/openai_codex/client.py, quindi esamina start() e il percorso di chiusura sincrono utilizzato dai client asincroni. Usa il processo sostitutivo launch_args_override fornito con python -X dev ed esegui i test SDK pertinenti Treatendo le ResourceWarning come errori. Fatto significa che il processo è stato terminato e raccolto, i thread del reader si sono fermati, tutte e tre le pipe sono chiuse e non rimane alcuna ResourceWarning.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
What issue are you seeing?
In the Python SDK, CodexClient.close() (sdk/python/src/openai_codex/client.py, lines 283–302 on main) never closes the app-server child process's stdout and stderr pipes. It closes stdin, terminates the process and joins the reader threads, but the two subprocess.PIPE file objects that start() opened (lines 268–278) stay open. They are only finalized whenever the Popen object is garbage-collected, and CPython reports each one:
ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='utf-8'>
ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='utf-8'>
AsyncCodex.close() / AsyncCodexClient.close() delegate to the same method, so every client the SDK creates leaves two handles to the garbage collector. A test suite that runs with -W error::ResourceWarning, or filterwarnings = error, fails on any test that closes a client. A long-running host that opens and closes many clients holds those handles until collection. On interpreters without prompt refcounting (PyPy), or when a reference cycle keeps the Popen alive, they can pile up.
A second, related gap, found by reading the code but not reproduced: if proc.wait(timeout=2) raises (for example subprocess.TimeoutExpired because the app-server doesn't exit within 2 s of SIGTERM on POSIX), close() calls proc.kill() but never waits for the process afterwards. On POSIX that leaves a zombie until the Popen is collected, and Popen.__del__ then warns ResourceWarning: subprocess <pid> is still running. The bare except Exception: also hides any other failure from terminate() / wait().
What steps can reproduce the bug?
This needs no Codex installation or sign-in. launch_args_override starts a stand-in process that just waits on stdin, which is enough because close() alone shows the problem.
"""CodexClient.close() leaves the app-server's stdout and stderr pipes open.
Needs no Codex install or sign-in: the launch override starts a stand-in process that waits on stdin.
Run with: python -X dev repro_close_leaks_pipes.py
"""
import gc
import sys
import warnings
import openai_codex
from openai_codex.client import CodexClient, CodexConfig
warnings.simplefilter("always", ResourceWarning)
print(f"openai-codex {openai_codex.__version__ if hasattr(openai_codex, '__version__') else '?'}, Python {sys.version.split()[0]}, {sys.platform}")
client = CodexClient(CodexConfig(launch_args_override=(sys.executable, "-c", "import sys; sys.stdin.read()")))
client.start()
proc = client._proc # kept only to show the pipes' state after close()
client.close()
print(f"after close(): returncode={proc.returncode}, stdin.closed={proc.stdin.closed}, stdout.closed={proc.stdout.closed}, stderr.closed={proc.stderr.closed}")
del proc, client
gc.collect()
print("done")
Output on Windows 11 with Python 3.14.2, identical for openai-codex 0.162.1 and 0.163.0 (latest on PyPI at the time of writing), shown here for 0.163.0 (stderr warnings first):
repro_close_leaks_pipes.py:25: ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='utf-8'>
del proc, client
ResourceWarning: Enable tracemalloc to get the object allocation traceback
repro_close_leaks_pipes.py:25: ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='utf-8'>
del proc, client
ResourceWarning: Enable tracemalloc to get the object allocation traceback
openai-codex 0.163.0, Python 3.14.2, win32
after close(): returncode=1, stdin.closed=True, stdout.closed=False, stderr.closed=False
done
AsyncCodex and AsyncCodexClient close through this same method. We first saw the warnings in an acceptance suite that runs the production async client against a mediated app-server process.
What is the expected behavior?
After close() returns:
- The child process has exited and been waited for (reaped), including on the
kill()path. - The reader threads have finished.
- stdin, stdout and stderr are all closed.
- No
ResourceWarningis emitted when the client is garbage-collected.
A possible fix in CodexClient.close():
if proc.stdin:
proc.stdin.close()
try:
proc.terminate()
proc.wait(timeout=2)
except subprocess.TimeoutExpired:
proc.kill()
proc.wait()
# The process has exited, so both reader threads reach EOF; join them before closing the pipes they read.
if self._stderr_thread and self._stderr_thread.is_alive():
self._stderr_thread.join(timeout=0.5)
if self._reader_thread and self._reader_thread.is_alive():
self._reader_thread.join(timeout=0.5)
for stream in (proc.stdout, proc.stderr):
if stream is not None:
stream.close()
Closing the pipes after the threads are joined avoids closing a file object another thread is still iterating. Catching subprocess.TimeoutExpired instead of Exception keeps unexpected failures visible. Alternatively, with proc: around the teardown closes all three pipes and waits.
Additional information
- Package:
openai-codex0.162.1 and 0.163.0 (sdk/pythonin this repo). The code is unchanged onmain. - Python 3.14.2 on Windows 11. The pipe leak is platform-independent. The missing wait after
kill()matters mainly on POSIX. - This is separate from #26984. That issue covers the CLI leaking pipes and orphan processes for MCP stdio servers it starts; this one is the Python SDK's own handles to the app-server process.
- Our workaround would be to close
proc.stdout/proc.stderrourselves afterclose(). That means reaching intoCodexClient._proc/AsyncCodexClient._sync, which are private, so we'd rather see it fixed in the SDK.
- Lingua principale
- Rust
- Stelle
- 133k
- Fork
- 21.1k
- Merge medio
- 1m
- PR unite (30g)
- 997
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di openai/codex
-
CI blob-size checker skips symlink-to-regular-file changes above its size limitForse già presa @akhil9tiet l’ha presa oggi. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
openai/codex#59650 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
bug CLI enhancement TUI
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
I maintainer di solito rispondono entro 1 giorno
-
bug memory windows-os
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
I maintainer di solito rispondono entro 1 giorno
-
Skill Creator quick validator rejects standard compatibility frontmatterForse già presa @akhil9tiet l’ha presa 5 giorni fa. Apertabug skills
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
openai/codex#58538 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di openai/codex
Issue simili
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 73/100
I maintainer di solito rispondono entro 1 giorno
-
🐞 bug 🧩 bevy_gantz_egui
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
nannou-org/gantz#500 ·
I maintainer di solito rispondono entro 1 giorno
-
[Feature]: Fedora 45 repoApertaenhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
metasequoiaime/msime#10989 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
fritzprix/libr-agent#2612 ·
I maintainer di solito rispondono entro 1 giorno
-
find: -printf %h drops a doubled slashForse già presa @qodelicious l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno