`notify` silently stops firing on long threads: payload passed as single argv exceeds Linux MAX_ARG_STRLEN (execve E2BIG)
What happened
The external notify hook silently stops firing once a thread grows long enough. Short/new threads keep working, which makes this very confusing: the config is valid, the script is valid, codex exec on a fresh thread fires the hook — but an established long-running thread never triggers it again. No error is surfaced anywhere (no log, no stderr, nothing in the TUI).
Root cause
Codex passes the notification event to the external program as a single command-line argument:
notify = ["bash", "/home/user/.codex/notify.sh"]
# → execve("bash", ["bash", ".../notify.sh", "<entire JSON as one arg>"])
The JSON payload for agent-turn-complete includes the thread's entire cumulative input-messages history, so it grows without bound over the life of a thread.
On Linux, a single execve argument is limited to MAX_ARG_STRLEN = 32 pages = 131072 bytes (with 4 KiB pages). Once the payload crosses that, spawning the notify program fails with E2BIG — and the failure appears to be swallowed silently, so notifications just stop.
Evidence
My notify script logs every event it receives to a file. The sizes of the last successfully delivered payloads speak for themselves (limit = 131072):
130197 bytes event_2026-07-22_12-13-20.json
131039 bytes event_2026-07-22_12-57-14.json <- 33 bytes below the limit
130785 bytes event_2026-07-22_18-05-44.json
130633 bytes event_2026-07-22_18-40-21.json <- last one ever delivered for this thread
The next day, after a few more user messages (~1.3 KB) were added to the same resumed thread, the hook never fired again for it. Fresh threads on the same binary/config fire fine.
The per-argument limit is easy to confirm independently:
$ A=$(head -c 131000 /dev/zero | tr '\0' x); /bin/echo "$A" >/dev/null && echo ok
ok
$ A=$(head -c 131100 /dev/zero | tr '\0' x); /bin/echo "$A" >/dev/null
bash: /bin/echo: Argument list too long
Reproduction
- Linux, any
notifyprogram configured inconfig.toml(mine just appends the received JSON to a file). - Drive a single thread until the cumulative size of its user messages approaches ~130 KB (large pasted messages get you there quickly), keep the thread going via
resume. - Observe: the notify program stops being invoked entirely, with no error reported. New threads still work.
Environment
- codex-cli 0.145.0 (also reproducible conceptually on any version that passes the payload via argv)
- Linux 6.12 (Manjaro), x86_64, 4 KiB pages
notify = ["bash", "~/.codex/notify.sh"]in~/.codex/config.toml
Suggested fixes
Any of these would solve it:
- Deliver the payload via stdin instead of argv (the new hooks engine already does this for command hooks — same approach).
- Truncate/cap
input-messagesin the notify payload (e.g., last N messages or last N KB). Arguably the full thread history shouldn't be in a notification payload at all —last-assistant-messageplus the last user message covers the actual use case. - At minimum, log the spawn error: an
E2BIG(or any exec failure) from the notify program currently vanishes, which makes this bug look like random breakage (see e.g. #8929, where notifications also stopped "midway through" a session — plausibly the same cause).