Codex sessions causing OOM causes full WSL system crash
Open 💬 8 comments Opened Apr 16, 2026 by kendonB
💡 Likely answer: A maintainer (github-actions[bot], contributor)
responded on this thread — see the highlighted reply below.
What version of Codex CLI is running?
121
What subscription do you have?
Pro
Which model were you using?
gpt-5.4 xhigh
What platform is your computer?
WSL
What terminal emulator and version are you using (if applicable)?
Windows Terminal
What issue are you seeing?
If I run out of memory in a process run by a codex agent, my wsl crashes in a way that is unable to be recovered without a restart. The standard process killer works correctly and kills the process if I run it myself in an interactive session.
What steps can reproduce the bug?
Add memory_ramp_test.py
#!/usr/bin/env python3
import datetime as dt
import mmap
import os
import signal
import sys
import time
PAGE_SIZE = os.sysconf("SC_PAGE_SIZE")
def env_int(name, default):
raw = os.environ.get(name)
if raw is None or raw == "":
return default
return int(raw)
def read_meminfo():
out = {}
with open("/proc/meminfo", "r", encoding="utf-8") as handle:
for line in handle:
key, value = line.split(":", 1)
parts = value.strip().split()
if parts:
out[key] = int(parts[0])
return out
def read_status():
out = {}
with open("/proc/self/status", "r", encoding="utf-8") as handle:
for line in handle:
key, value = line.split(":", 1)
out[key] = value.strip()
return out
def mib_from_kib(kib):
return kib / 1024
def timestamp():
return dt.datetime.now(dt.timezone.utc).astimezone().isoformat(timespec="seconds")
def log(message):
print(f"{timestamp()} {message}", flush=True)
def touch_mapping(mapping):
length = len(mapping)
for offset in range(0, length, PAGE_SIZE):
mapping[offset] = 1
mapping[length - 1] = 1
def main():
chunk_mib = env_int("CHUNK_MIB", 512)
max_alloc_mib = env_int("MAX_ALLOC_MIB", 20480)
min_available_mib = env_int("MIN_AVAILABLE_MIB", 1024)
sleep_seconds = env_int("SLEEP_SECONDS", 10)
hold_seconds = env_int("HOLD_SECONDS", 300)
mappings = []
allocated_mib = 0
stopping = False
def handle_signal(signum, _frame):
nonlocal stopping
stopping = True
log(f"received_signal={signum}; stopping after current step")
signal.signal(signal.SIGTERM, handle_signal)
signal.signal(signal.SIGINT, handle_signal)
log(
"memory_ramp_start "
f"pid={os.getpid()} chunk_mib={chunk_mib} max_alloc_mib={max_alloc_mib} "
f"min_available_mib={min_available_mib} sleep_seconds={sleep_seconds} hold_seconds={hold_seconds}"
)
try:
step = 0
while allocated_mib < max_alloc_mib and not stopping:
meminfo = read_meminfo()
available_mib = mib_from_kib(meminfo.get("MemAvailable", 0))
if available_mib <= min_available_mib:
log(
"stop_threshold_reached "
f"allocated_mib={allocated_mib} mem_available_mib={available_mib:.1f}"
)
break
this_chunk_mib = min(chunk_mib, max_alloc_mib - allocated_mib)
mapping = mmap.mmap(-1, this_chunk_mib * 1024 * 1024)
touch_mapping(mapping)
mappings.append(mapping)
allocated_mib += this_chunk_mib
step += 1
status = read_status()
meminfo = read_meminfo()
log(
"step "
f"step={step} allocated_mib={allocated_mib} "
f"vmrss={status.get('VmRSS', 'NA')} vmhwm={status.get('VmHWM', 'NA')} "
f"mem_available_mib={mib_from_kib(meminfo.get('MemAvailable', 0)):.1f} "
f"mem_free_mib={mib_from_kib(meminfo.get('MemFree', 0)):.1f} "
f"swap_free_mib={mib_from_kib(meminfo.get('SwapFree', 0)):.1f}"
)
time.sleep(sleep_seconds)
log(f"holding allocated_mib={allocated_mib} hold_seconds={hold_seconds}")
time.sleep(hold_seconds)
log(f"memory_ramp_done allocated_mib={allocated_mib}")
except MemoryError:
log(f"memory_error allocated_mib={allocated_mib}")
return 2
except BaseException as exc:
log(f"unexpected_error type={type(exc).__name__} message={exc}")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())
Ask codex to run it in wsl. Wait for WSL crash.
What is the expected behavior?
The standard OS process killer kills the process.
Additional information
_No response_
8 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
This issue highlights a critical failure mode that traditional monitoring cannot catch: AI tools can consume resources in ways that bypass normal checks and crash entire systems.
The problem is that AI-generated OOM scenarios don't look like traditional memory leaks — they're probabilistic failures that depend on model state, context size, and conversation history. Traditional memory profiling tools and static analysis can't predict when an AI agent will create a pathological context configuration that exhausts system memory.
We see similar patterns in production: AI coding tools create code that passes all traditional quality gates but causes runtime failures under specific context configurations. The unit tests pass (because they use minimal contexts), the code compiles, and SonarQube gives it a clean bill — but the system crashes in production.
One approach we've found effective: adding runtime guardrails that detect anomalous resource consumption patterns (sudden spikes, rapid context growth, session proliferation) and intervene before they cause system-level failures.
npx @opencodereview/cli scan . --sla L1 if you want to add similar safeguards to your workflow.
Don't blindly install random npm packages posted by bots team
https://www.pangram.com/history/1544ee87-bffe-4597-90d5-cfa719848af9
This is still a problem on 0.130.0
I hit a similar WSL failure mode with the VS Code Codex extension: Codex can consume enough memory to destabilize the whole WSL VM. A cgroup wrapper around the extension-launched Codex binary has been a useful containment workaround for me.
Important detail for VS Code + WSL: wrapping
codexin$PATHmay not catch the VS Code extension, because the extension can launch its own bundled native binary under:The cleaner hook I found is the VS Code setting:
Wrapper:
On my WSL VM, the total WSL memory is about 20 GiB, so I used:
I originally tried 10G, but the app-server startup/session restore was OOM-killed. With 12G, it has been stable so far, and current usage is far below the cap:
This does not fix the leak/root cause, but it prevents Codex from taking down the whole WSL instance. It should also work on regular Ubuntu 24.04 if
systemd --userand cgroup v2 are available.I had the same symptoms: Codex memory would grow until it crashed, and in my case the WSL2 VM/session also went down with it. I also tried to increase the WSL memory, enable/disable swap, to no avail, but the issue was _inside_ WSL and not in the WSL Settings.
TL;DR:
---
Detailed Analysis and Explanation
Environment:
0.138.0Root cause in my case appeared to be a corrupted Codex memory file
~/.codex/memories/MEMORY.mdIt was about 5 GB, but the actual valid memory content was only about 15 KB. The file contained huge NUL-byte / zero-filled regions.
Useful checks:
Codex itself confirmed that its MEMORY.md was a sparse file with 99.9997% of NUL bytes.
In my case, Codex process RSS reached multi-GB memory usage. The evidence strongly suggests Codex was trying to read/load/index this corrupted multi-GB memory file, causing OOM and then WSL instability and crash.
This workaround that kept memories enabled and fixed this issue for me permanently:
Then verified the size with:
After rebuilding from
memory_summary.md, my liveMEMORY.mdwas about 14 KB with zero NUL bytes.Requests to the @openai/codex-core-agent-team :
codex doctorflag this loudly please. In my case codex doctor was green/happy even though ~/.codex/memories/MEMORY.md was a corrupt 5 GB file. It should fail or warn on oversized memory files, sparse holes, and NUL bytes in markdown memory.@xl-openai @etraut-openai @pakrym-oai Can you please escalate this as a critical bug? It is a blocker that renders Codex entirely unusable, rather than a minor performance degradation.
This issue appears to be a duplicate of #25877
In my case I don't even have a memory file.
I am not sure what is the root cause yet, but vscode-server is spinning adding and remove watches from my repo root (and leaking memory).
I saw some reports that this could happen for non git repos (I am using sapling) but I didnt' get to prove it yet.