Repository navigation
[Linux Desktop][26.924] Electron runtime replaces libuv's SIGCHLD handler with an empty function: children are never reaped, so shell env times out, "Git is unavailable", threads never load #48554
Description
Summary
On Linux, ChatGPT Desktop 26.924.20706 and 26.924.22138 install an empty SIGCHLD handler in the main (browser) process after startup, replacing libuv's handler. libuv installs its SIGCHLD handler only once, when the first child is spawned, so from that point no child process is ever reaped. Every child_process promise in the main process (and its worker threads) waits forever.
This appears to be the root cause of #48419, #48397, #48225 and #48417, and likely of #48482. The same mechanism as #38505 (zombie accumulation on macOS) may be involved there too.
Environment
- ChatGPT Desktop 26.924.22138 (build 11645, build commit 2e782921399a788a842b74ee1944a2e1e6e003a1), official .deb, x86-64
- Ubuntu 26.04, Linux kernel 7.0, KDE Plasma
- 26.917.71314 is not affected. Both builds bundle libuv 1.52.1; the Electron ("owl") runtime archive changed between them.
Symptoms (all explained by the cause)
Failed to load shell env caller=startup detail="Timed out after 5000ms."on every start (the login-shell probe finishes in ~0.2 s when run by hand)Worktree archive will be retried errorMessage="Git is unavailable"although git works (the Git availability probe never gets its exit status)- Opening a local thread:
thread_hydration ... outcome=failure reason=timeout; hydration stops aftermetadata_readybecauseprepare()awaits child processes;thread/resumeis never sent - New messages are queued and new threads never start
psshows zombie (Z) children of the ChatGPT main process:bash,git,ps,gh,tar,codex, growing over time
Evidence
- Zombies:
ps -o pid,stat,comm --ppid <ChatGPT main pid>listsZchildren for every short-lived helper. - SIGCHLD delivered, nothing reaps it: a bpftrace probe on
signal:signal_deliver(sig 17) for the main process shows SIGCHLD delivered to the main thread. Nowait4/waitidfollows, and the handler writes nothing to libuv's signal pipe. - The installed handler is empty: the
sa_handleraddress resolves to a CFI jump-table entry (0x117d9f78in the 26.924.22138ChatGPTbinary), which jumps to an identical-code-folded empty function at0x11ce69c8(push rbp; mov rbp,rsp; pop rbp; ret). - Where it is installed: the function at
0x723eb00calls an initializer (0x723eb70). When that returns 0, it callssigaction(17 /*SIGCHLD*/, {sa_handler = <empty>, sa_flags = 0}, NULL). The function is reached through pointers in.data.rel.ro(0x1244c698,0x1244c758), i.e. a vtable. Addresses are virtual addresses in the unmodified 26.924.22138 binary. - Knock-on effect: in the broken state
SigCgtof the main process stays at0x17381ecff. execa'ssignal-exithooks remain registered because no child ever exits. With the fix below it returns to0x1000104c8.
Controlled A/B test
Isolated headless instances of the installed build (Xvfb, private CODEX_HOME, Electron user data dir and TMPDIR, private copy of the bundled codex, no sign-in), 60 s each:
| zombie children | shell env | app-server | |
|---|---|---|---|
| stock | 4-5 and rising | Failed to load shell env |
connected |
| with preload guard | 0 | loads | connected |
On the real signed-in profile with the guard: saved threads render (including one with ~1,400 prior messages), messages send, new threads start, and 0 unreaped children remain after hours of use.
Workaround (no downgrade)
Preload a small library that refuses only a sigaction(SIGCHLD) call whose handler is an empty function while a real handler is already installed. Every other call passes through, and the library strips itself from LD_PRELOAD so child processes don't inherit it. Launch with LD_PRELOAD=/path/to/sigchld-guard.so /usr/lib/chatgpt/ChatGPT. Don't launch through the chatgpt shell wrapper: the wrapper's sh loads the library first, and the library removes the variable before the app starts. Build with gcc -O2 -fPIC -shared -o sigchld-guard.so sigchld-guard.c -ldl.
sigchld-guard.c (x86-64)
#define _GNU_SOURCE
#include <dlfcn.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef int (*sigaction_fn)(int, const struct sigaction *, struct sigaction *);
static sigaction_fn real_sigaction;
static sigaction_fn resolve(void)
{
if (real_sigaction == NULL)
real_sigaction = (sigaction_fn)dlsym(RTLD_NEXT, "sigaction");
return real_sigaction;
}
/* Follow endbr64 and direct jumps (CFI jump tables) to the function body. */
static const unsigned char *body(const unsigned char *p)
{
for (int hops = 0; hops < 4; hops++) {
if (p[0] == 0xf3 && p[1] == 0x0f && p[2] == 0x1e && p[3] == 0xfa)
p += 4;
if (p[0] == 0xe9) {
int32_t rel;
memcpy(&rel, p + 1, sizeof rel);
p += 5 + rel;
} else if (p[0] == 0xeb) {
p += 2 + (int8_t)p[1];
} else {
break;
}
}
return p;
}
static int is_empty_function(void (*handler)(int))
{
static const unsigned char framed_ret[] = {0x55, 0x48, 0x89, 0xe5, 0x5d, 0xc3};
const unsigned char *p = body((const unsigned char *)handler);
return p[0] == 0xc3 || memcmp(p, framed_ret, sizeof framed_ret) == 0;
}
static int is_real_handler(const struct sigaction *sa)
{
if (sa->sa_flags & SA_SIGINFO)
return sa->sa_sigaction != NULL;
return sa->sa_handler != SIG_DFL && sa->sa_handler != SIG_IGN;
}
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
{
sigaction_fn next = resolve();
if (next == NULL)
return -1;
if (signum == SIGCHLD && act != NULL && !(act->sa_flags & SA_SIGINFO)
&& is_real_handler(act) && is_empty_function(act->sa_handler)) {
struct sigaction current;
if (next(SIGCHLD, NULL, ¤t) == 0 && is_real_handler(¤t)) {
if (oldact != NULL)
*oldact = current;
return 0;
}
}
return next(signum, act, oldact);
}
__attribute__((constructor)) static void drop_from_environment(void)
{
resolve();
unsetenv("LD_PRELOAD");
}Suggested fix
Don't install a SIGCHLD handler in the Electron runtime after Node/libuv has installed one. Or save and chain to the previous handler, or install it before Node's first spawn. The installer at 0x723eb00 appears to be new in the runtime shipped with 26.924.x.
Activity
github-actions commentedon Sep 26, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
jointsome0-lgtm commentedon Sep 27, 2026
Independent confirmation, plus a handoff procedure for another affected laptop.
We diagnosed and repaired the same failure on September 26, before finding this issue. On ChatGPT Desktop 26.924.22138, Linux x86-64, kernel 7.0.0-34-generic:
bundled_plugins_reconcile_startedhad no corresponding completion or failure. Instrumentation narrowed the pending await to thepsinvocation in browser native-host cleanup.bash,git,ps, and other children. A NodeSIGCHLDlistener received no callback, including after explicitly sending SIGCHLD.Restoring Node/libuv's handler for SIGCHLD in the running process immediately released the pending waits. Plugin reconciliation completed,
child_process.execFile('/usr/bin/git', ['--version'])returned successfully, and the user confirmed that the local chat opened and displayed messages. After installing the workaround and restarting the normal app, reconciliation completed again and no zombie children appeared in the final process check. No conversation history or authentication state was deleted.We did not trace the code which installed the conflicting handler. The binary-level investigation in the issue above supplies evidence beyond our own test.
Instructions for an affected second laptop
The same visible symptom on a second laptop is not yet confirmation of this mechanism. These instructions can be handed to Codex CLI in a terminal, independently of the broken Desktop UI.
Record the installed build and identify the main process. On a Debian package installation:
dpkg-query -W -f='${Version}\n' chatgpt uname -mprs ps -C ChatGPT -o pid,ppid,stat,argsSelect the main executable process without a
--type=...argument. Inspect its children usingps --ppid MAIN_PID -o pid,ppid,stat,etime,comm. Confirm that short-lived helpers remain in stateZacross repeated observations. Look for the shell-environment timeout and a plugin-reconciliation start without completion in the Desktop logs. Redact paths and account/session identifiers before publishing logs.Check whether an upstream update already fixes it. Do not apply a build-specific workaround to an unrelated version or architecture merely because a chat is loading slowly.
Choose one workaround, with a backup. The issue body above provides a complete x86-64 preload-guard source and build command:
Save and review the source from the issue body before compiling. Build it in a dedicated user-owned repair directory. That guard is the original reporter's tested workaround; our independent test used the N-API restoration described below. They are alternative approaches, not two patches to stack.
For the preload guard, quit only Desktop, then test a direct executable launch. Preserve any ongoing standalone Codex/Claude CLI sessions. Confirm the executable path on that laptop. For the package path in this report:
Use the actual executable, not
/usr/bin/chatgpt, because the shell wrapper can consume the guard's one-process environment setup. IfLD_PRELOADis already configured, investigate it before replacing it. Do not add the guard to/etc/ld.so.preloador a global shell environment.Verify the outcome before making the launcher persistent. Open an existing local chat, confirm that its messages render, check that plugin reconciliation completes, and inspect the main process for accumulating zombie children. Verify Git availability through Desktop. If the test succeeds, a dedicated user launcher can set LD_PRELOAD for that executable only. Keep the original launcher available.
Rollback and updates. For the preload approach, quit Desktop and use its original launcher without the guard. Remove the dedicated launcher if one was created. Recheck the unmodified app after an upstream update before carrying the workaround forward. If instead modifying
app.asar, retain the exact original, check its version/hash before patching, and restore it only to the matching build.The independently tested restoration mechanism
Our local patch used a short main-process bootstrap and an N-API addon, scoped to the Desktop process. The essential native operation was:
The bootstrap first registered a temporary
process.on('SIGWINCH', listener)to obtain Node/libuv's handler, called the addon, then removed that exact temporary listener infinally. This snippet describes the mechanism, not a standalone installer. It must execute inside the affected main process. Running it in a separatenodeprocess does not repair Desktop.The final local patch had no inspector or remote-debugging port. It did not disable plugin checking or bypass its waits. Initial shell-environment hydration happened before our bootstrap and could still incur its five-second timeout, so our patch was a recovery workaround rather than a complete upstream fix.
Paste-ready task for Codex on the second laptop
beyondfashion-ai commentedon Sep 27, 2026
Confirming on WSL2 (Ubuntu 24.04 "noble" under WSL2 on Windows, X11
--ozone-platform=x11, official.deb). Same regression on 26.924.20706 and 26.924.22138; 26.917.71314 works. Adding a few data points that may help narrow it down.Zombie accumulation (main process children)
apt purge+ reinstall + a brand-new empty profile dir): 8–11<defunct>children of the mainChatGPTprocess (git,gh,bash,ps,codex).~/.codex: 0 zombies.Where resume stalls (renderer side, traced with CDP logpoints)
maybe_resume_started→readThread→ writable roots →resumeState=resuming→metadata_ready→prepare()→ thread-start config builder.fetchProxyConfig(get-copilot-api-proxy-info) returns in ~290 ms, butfetchCodexConfig→ main-process IPCmcp-codex-confignever resolves (tested with several differentcwdvalues, including/tmp).thread/resumeis therefore never sent.buildMcpCodexConfigawaits the browser-use/bundled-plugin sync state before returning. On 26.924 the log showsbundled_plugins_reconcile_startedbut neverbundled_plugins_reconcile_completed; on 26.917 it completes. This fits the unreaped-child explanation above: the reconcile, shell-env probe and git probe all wait on child exit events that never arrive.Things that did NOT help on 26.924 (ruled out)
queue_1.sqliteandqueued-follow-upsin.codex-global-state.json)[features]key fromconfig.tomlDowngrade note
26.924 applies new SQLite migrations on first start (
state_5.sqlitev56–57,thread_history_1.sqlitev7,codex-dev.db20260914…/20260924…). 26.917.71314 still started fine against the migrated DBs here and resumed threads normally, but back up~/.codex/*.sqliteand~/.codex/sqlite/before downgrading. Workaround used:sudo apt-get install --allow-downgrades ./chatgpt_26.917.71314_amd64.deb sudo apt-mark hold chatgpt # otherwise unattended-upgrades re-installs 26.924 the next morningMobile remote-control and the standalone CLI (
codex resume <id>, 0.157.1) kept working against the same threads throughout, consistent with the problem being confined to the desktop main process.Zburatorul commentedon Sep 27, 2026
Confirming on Debian 13 (x86-64, X11), 26.924.20706 and 26.924.22138; 26.917.71314 is unaffected. One addition that I think changes where the regression is: 26.917.71314 installs the same empty SIGCHLD handler. What changed in 26.924 is when the first child process is spawned relative to that
sigactioncall.I ran A/B traces of both builds under identical isolation: unpacked
.deb, Xvfb, private D-Bus, throwaway HOME/XDG dirs, CODEX_HOME and--user-data-dir, no sign-in. The command wasstrace -f -e trace=rt_sigaction,wait4,clone,clone3,execve -e signal=SIGCHLD. Times are relative to process start.uv__signal_handler)bash -ilcprobeBoth builds point SIGCHLD at the same kind of CFI jump-table slot, 0xd8 below libuv's handler, jumping to the same folded empty function (
push rbp; mov rbp,rsp; pop rbp; ret):ChatGPT: slot0x118268c8→jmp 0x11c3a198(empty); libuv handler0x118269a0ChatGPT: slot0x117d9f78→jmp 0x11ce69c8(empty); libuv handler0x117da050In 26.917 the empty handler is harmless: libuv installs its handler afterwards, on the first spawn. In 26.924, the reworked startup (
early-bootstrap.js→ shell-env hydration) spawnsbashbefore the native code runs. libuv only installs its handler once, so it never recovers.This suggests two independent fixes:
sigaction(SIGCHLD, NULL, &old), or chain to the old handler). This is what the preload guard above emulates.Either one alone should restore reaping. A startup self-check (spawn
true, assertexitarrives) would catch this class of regression.strace, 26.924.22138 (main process, SIGCHLD-related)
strace, 26.917.71314 (main process, SIGCHLD-related)
ChrisLauinger77 commentedon Sep 27, 2026
Another reproduction: ChatGPT Desktop for Linux 26.924.22138 on Debian forky/sid. Since the September 26 update, new Codex and Work local tasks stay at ‘Your task is being started’ indefinitely. Git works locally (
/usr/bin/git, version 2.53.0), but desktop logs show a 5-second shell environment timeout and repeated ‘Git is unavailable’ messages. The standalone Codex CLI works. I have not tested the SIGCHLD mechanism.jasonsperske commentedon Sep 27, 2026
Confirming on Ubuntu 26.04.1 LTS, kernel 7.0.0-34-generic, x86-64, X11, official
.debvia the auto-configured apt repo. Installed package:chatgpt 26.924.20706(bundled app-server0.158.0-alpha.2). Everything matches the mechanism described here.Timeline (from
/var/log/dpkg.logand~/.codex/logs_2.sqlite)26.901.51231 → 26.924.20706; on next launch, state DB migrations 53–57 and thread-history migration 7 all applied successfullythread/start,thread/resumeorturn/startrequests have reached the app-server. Existing local threads spin forever. New tasks sit at "Starting your task", and follow-up messages stay queued.chatgpt-conversation-resume-tokens-v1entry had no effect.Zombies and signal mask (40 s after a normal launch)
This is the same
SigCgtvalue reported above for the broken state.Main-process stdout (launched from a terminal)
bash -ilc truetakes 0.20 s by hand, and/usr/bin/git2.53.0 works.Renderer vs. app-server (CDP on the main window, plus app-server TRACE logs)
maybe_resume_started connectedEnvironmentIds=undefined environmentIds=undefined previousResumeState=needs_resume vmEvent=thread_resume_requestedfor each thread I open.thread/list,thread/read,thread/attachment/list,thread/queue/listandconfigRequirements/readin 2–5 ms. It never receivesthread/resume, even with TRACE logging.client.performance.span name=thread_navigation outcome=aborted reason=superseded threadState=cold, with marks stopping athydration_started.thread_history_projection_state.next_rollout_byte_offsetequals its rollout file's size, androllout_migration_skipped_rolloutsis empty.Happy to run a strace or GDB A/B test if it would help. The
SigCgtvalue and zombie list alone seem enough to show it's the same defect.daseus commentedon Sep 27, 2026
Another independent confirmation on KDE neon, x86-64, native Wayland.
I could neither open previous conversations nor start new ones in the ChatGPT desktop app. Both Codex and Work were affected. The standalone Codex CLI continued working normally.
We reproduced this with both 26.924.20706 and 26.924.22138. The local backend could list and read existing conversations, but opening them in the app never reached
thread/resume. The logs showed the same five-second shell timeout and “Git is unavailable” errors. Completedbash,git, andpsprocesses remained as zombies under the desktop process, even though they had exited successfully.What got me working again:
CODEX_CLI_PATH.My local history was preserved; no profile reset or history deletion was needed. We did not trace the SIGCHLD handler itself, so this confirms the matching symptoms and affected versions, rather than independently proving that exact mechanism.
sonytalk-W commentedon Sep 27, 2026
Independent reproduction on Ubuntu Linux with the official
chatgptDebian package 26.924.22138 (build 11645, commit2e782921399a788a842b74ee1944a2e1e6e003a1). Kernel: 7.0.0-34-generic, x86_64. Bundled runtime identifies asowl; its version file reports42.3.0.User-visible reproduction
A first-response telemetry event recorded
outcome=failure reason=timeout durationMs=120013. Background configuration requests and account event subscriptions still worked.Independent process-level evidence
Failed to load shell env ... Timed out after 5000msandGit is unavailable./usr/bin/git --versionsucceeds outside the app (git version 2.53.0).bash,git,gh, andpschildren accumulate in zombie state beneath the desktop main process.strace -f -tt -e trace=processcapture on 2026-09-27 confirmed:Parent PID
26833did not reap child26854during the capture, and the child remained a zombie. Two Git children likewise exited with status 0 and remained zombies:In an earlier run, explicitly delivering
SIGCHLDto the desktop main process did not reap its 12 existing zombie children. The observed main-processSigCgtwas000000017381ecff, matching the broken-state mask described above.This independently corroborates successful child execution, SIGCHLD delivery, and failed completion/reaping on another installation. We did not trace handler registration or test the preload workaround, so this comment does not independently establish the handler-overwrite mechanism or claim a successful fix. No app binaries, user settings, or conversation data were modified. The tracer has been stopped and detached.
Dango233 commentedon Sep 27, 2026
Adding confirmation on ARM64 / aarch64: Ubuntu 24.04 running under PRoot on Android, using the official ChatGPT Linux package, an X11/Xvfb desktop, and
--no-sandbox --disable-gpu.26.924.22138 reproduced the failure; 26.917.71314 restored normal loading on rollback. This adds another environment to the existing Linux reports, rather than establishing a PRoot-specific bug.
Observed in the affected version:
thread/readsucceeded, but loading did not reach athread/resumerequest.refresh_startedwithout completion.bash,ssh,git, andcodexchildren remained zombies under the desktop main process.PRAGMA quick_checkchecks returnedok; standalonessh -Gand Node subprocess tests completed.Local SIGCHLD instrumentation observed one handler registration followed by a different registration during startup (
SA_RESTARTfirst, flags0later). We did not symbolize the ARM64 handlers, so their precise identities are not independently established by our trace. Both bundled runtimes passed minimal subprocess tests when helpers were first spawned afterapp.whenReady(); the older runtime with newer application resources still reproduced the failure.We tested the same early-bootstrap deferral described in the Gentoo comment on #48212:
The remaining startup and permission/policy initialization calls were retained, with the ASAR metadata updated accordingly.
With the existing profile, SSH catalog
load_completed/refresh_completedreturned, and an existing local conversation rendered successfully.thread/resumecompleted in 837 ms in the test copy and 1255 ms in the patched installed package, followed bymaybe_resume_success. No zombie direct children were observed at the follow-up checks.This supports the startup-order diagnosis and extends the workaround evidence to Android-hosted ARM64 PRoot. It is a local diagnostic workaround, not a validated production fix: we verified existing conversation loading and SSH catalog refresh, but did not validate a new SSH connection, a new agent turn, or long-running stability. GPU rendering artifacts were a separate issue; disabling GPU acceleration alone did not resolve the loading failure.
Diagnosis and drafting were assisted by Codex; observations come from executed local checks and application logs. No device branding, private addresses, account/session identifiers, or conversation contents are included.
WaterWhisperer commentedon Sep 27, 2026
Update: confirmed that downgrading from 26.924.22138 to 26.917.71314 fixes the issue on Ubuntu 24.04 x86_64. Existing conversations load and accept messages again, and the model selector is restored. No profile/cache/config data was cleared; only the package version changed.
Reproduced on Ubuntu 24.04 x86_64 with ChatGPT Desktop 26.924.22138.
Existing conversations do not load normally. They only become visible after opening “View activity”, but I cannot continue sending messages in existing conversations. The model selector/tab is also missing.
My APT cache still contains 26.917.71314, so I’m downgrading to that version now. I’ll update this comment if the rollback fixes the issue.
SoongVilda commentedon Sep 27, 2026
I’m also affected on CachyOS (Arch-based), x86_64, and the preload workaround described in this issue works for me.
Environment:
chatgpt-bin 26.924.22138-1from theopenai-chatgptrepositoryFor reproducibility, below is the source I used to build
sigchld-guard.so, followed by the build and launch commands.Full guard source and build instructions (x86-64)
Create the directory:
Save the following as
~/.local/lib/chatgpt-sigchld/sigchld-guard.c:Compile it with GCC:
Check the generated library:
It should report an ELF 64-bit x86-64 shared object. Only continue if compilation succeeded.
After compiling, I fully quit ChatGPT, including any background instance, and launch the actual executable directly:
The Wayland option matches my desktop setup.
The wrapper warning also applies to this package:
/usr/bin/chatgptresolves to a shell launcher, so the preload must be applied directly to/usr/lib/chatgpt/ChatGPT. Otherwise, the wrapper loads the guard and clearsLD_PRELOADbefore ChatGPT starts.I’m using this only as a temporary, manually triggered workaround for
26.924.22138-1, without modifying the installed package or desktop launcher. The guard uses x86-64 instruction matching and should be reassessed after an update. ClearingLD_PRELOADprevents normal propagation to newly executed programs; fork-only children still inherit the loaded library.0xtaruhi commentedon Sep 27, 2026
Independent confirmation of the managed-SSH impact and a successful no-downgrade workaround on Fedora 44 x86-64.
chatgpt-26.924.22138-1.x86_64. Remote: Ubuntu 26.04 over SSH.SSH: local ssh config probe timed out after 5000msandSSH: codex path probe timed out after 60000ms. Direct SSH and remotecodex --versionreturned promptly. Short-livedssh,git,zsh, andpschildren remained as zombies under the desktop main process.0x117d9f78jumps to the empty function at0x11ce69c8(push rbp; mov rbp,rsp; pop rbp; ret), matching this issue's analysis.status=loadedin 144 ms; remote login-shell commands completed in about 0.76–0.80 s; and the managed remote connection transitioned fromconnectingtoconnected. The SSH process stayed up runningcodex app-server proxy, and there were 0 zombie children at a follow-up check after more than a minute.This adds end-to-end validation of a managed SSH connection, beyond SSH catalog refresh. Account identifiers, host addresses, and project paths are omitted.
18 remaining items
DenislavVelichkov commentedon Sep 28, 2026
Proposed upstream runtime change for this SIGCHLD regression. The diff targets
chrome/browser/chrome_browser_main_posix.ccfrom Chromium 154.0.8037.57, for application in OpenAI's Linux desktop runtime tree.Chromium's placeholder handler has a purpose when SIGCHLD is default, ignored, or configured with
SA_NOCLDWAIT: it allows later waits on children. The regression occurs when libuv already installed a waitable SIGCHLD handler and Chromium unconditionally replaces it. This change keeps the existing handler in that case, while retaining Chromium's placeholder for the other dispositions.Before release, please verify that a libuv SIGCHLD handler and its flags survive
PreEarlyInitialization, child exit callbacks run, and no zombies accumulate. Verify the default, ignored, andSA_NOCLDWAITcases still permitwaitpidto reap a child. In the full Linux desktop app, check shell setup, Git availability, existing chat resume, and a new task.The query and subsequent registration are separate calls. The runtime build should ensure no concurrent signal registration occurs between them; if that cannot be guaranteed, also move the early shell probe until after Chromium initialization. This is a source patch proposal. I verified that it applies cleanly to the matching Chromium source, but I cannot build or test OpenAI's desktop runtime from the public repository. Independent process-level confirmation of the same failure is in #48618.
ardaerturk commentedon Sep 28, 2026
What version of the Codex App are you using (From “About Codex” dialog)?
26.924.22138, build11645, official amd64.deb(verified from package metadata and logs).What subscription do you have?
Azure OpenAI API provider.
What platform is your computer?
Ubuntu 24.04.4 LTS, kernel
7.0.0-1014-azure, x86-64; XFCE/X11 through TigerVNC on an Azure VM.What issue are you seeing?
Existing threads stayed loading. Logs showed the 5000 ms shell-environment timeout and “Git is unavailable”;
bash,git,ps,gh, andcodexchildren remained zombies.What steps can reproduce the bug?
Launch this build and open an existing local thread. Restarting the app, rebooting the VM, and reinstalling the same official package did not resolve it.
What is the expected behavior?
Existing thread history loads.
Additional information
The issue's SIGCHLD preload guard resolved this on the same build and profile:
thread_hydration outcome=successandmaybe_resume_success.bundled_plugins_reconcile_completedappeared; no zombie children remained at the follow-up check.Applied through the desktop and systemd launch wrappers, gated to the package version and executable SHA-256. No packaged files, credentials, or history were reset;
dpkg -V chatgptreported no changes. New-task execution was not separately tested.jaenw commentedon Sep 28, 2026
This completely broke the Linux desktop build for everyone, aren't there any E2E tests?!?!
💩
zyhe16 commentedon Sep 28, 2026
Agreed, I don't even understand how they can make such mistakes...
iboware commentedon Sep 28, 2026
Fedora 44 reproduction and same-build recovery
I reproduced this with the official
chatgpt-26.924.22138-1.x86_64RPM on Fedora 44.rpm -V chatgptreports no modified package files.In the stock app, every local conversation I tried remained on the loading spinner. The app server returned successful
thread/readresponses, but the desktop never sentthread/resume. The main process retained exitedbash,git, andpschildren in zombie state. A fresh renderer profile and a phone hotspot did not change the behavior.For a controlled recovery check, I stopped one stock test instance and relaunched the same installed binary with the process-local SIGCHLD guard described in this issue, using the same renderer profile and Codex home. An existing conversation then rendered its saved messages. After the load, that main process had zero zombie direct children. The RPM and conversation databases were not patched or reset.
This result supports the SIGCHLD handler ordering diagnosis on Fedora too. The old/new startup trace explains why the regression appeared in 26.924 even though the no-op handler also existed in the earlier build. I would fix the runtime by preserving a previously installed, waitable SIGCHLD handler, as in the proposed source change, or by moving the first child spawn after Chromium initialization.
A useful release regression test would spawn a short-lived child on both sides of Chromium initialization, require Node's exit callback to run, and check that no zombie remains. The packaged Linux smoke test should then verify shell environment loading, Git detection, existing conversation resume, and starting a new local task.
VirelNode commentedon Sep 28, 2026
Confirmed on Ubuntu 24.04.5 LTS, x86-64, official Desktop DEB 26.924.22138. Thank you @axusnetworks for identifying the handler overwrite and publishing the original guard approach.
I published a build-scoped implementation, launcher, build instructions, and rollback steps for others experiencing the same failure:
https://gist.github.com/VirelNode/805b5274e0b680f70180c36be7fff8b2
Before: the local app-server initialized and answered metadata requests, but a simple GUI prompt remained at “Starting your task” without reaching
thread/start. The shell probe timed out at 5 seconds, Git was reported unavailable despite working in the terminal, and completed helper processes remained zombies. A fresh Desktop restart reproduced it.After: with the guard and the same installed application/profile, a new GUI prompt completed. After quitting and launching again through the repaired desktop entry, the saved conversation opened (
thread_hydration outcome=success, about 689 ms), and a follow-up GUI prompt completed too. The main process had zero zombie children at the follow-up check. The fresh-launch log had no shell-environment timeout or Git-unavailable error. The app-server did not inheritLD_PRELOAD.The launcher checks the installed executable SHA-256 before enabling the library:
23b753552181a8ea661681256c2dbf993fea1285fbc5c824478bad9cbdd45c91The guard only rejects the verified empty-handler replacement at the matching executable offset/bytes, while preserving an existing real handler. The installed jump and empty function were checked with disassembly. All other
sigactioncalls pass through. The launcher runs the executable directly; the library removes its preload environment before helpers spawn. A different executable hash, missing guard, or pre-existing preload makes the launcher run without this workaround.No installed binary,
app.asar, authentication, conversation history, or Codex configuration was patched/reset. Standalone terminal sessions remained running. The C source compiled with-Wall -Wextra -Werror; the published launcher passed shell syntax validation. The gist explains the small portability change from the tested absolute library path to a library beside the launcher.This is a temporary local workaround, not an official fix or a claim of full Desktop regression coverage. A permanent runtime fix is still needed. No private logs, conversation contents, machine identifiers, or credentials are included.
Posted with the affected user's authorization; investigated and verified with Codex CLI.
dimpy-cmd commentedon Sep 28, 2026
Confirming that this bug still exists in the official Fedora RPM chatgpt-26.924.22138-1.x86_64, tested on September 28, 2026.
Environment: Fedora 44, x86-64, kernel 7.2.7-200.fc44.x86_64, glibc 2.43-8.fc44. Desktop build 11645, commit 2e782921399a788a842b74ee1944a2e1e6e003a1.
Observed in the stock build:
Failed to load shell env ... Timed out after 5000msandGit is unavailable.Same-build workaround test: a process-local preload guard preserving an existing real SIGCHLD handler against replacement by an empty main-executable handler was compiled and tested, then used to restart the same installed binary with the existing profile. The guard logged that it prevented the replacement. Afterward:
thread/resume, 290 ms).outcome=success, with content visible in approximately 656 ms.This supports the reported SIGCHLD regression on Fedora 44. The workaround is temporary, scoped to the exact executable hash, and does not constitute an upstream fix. A complete new model-response turn was not separately verified during this test. No installed application files or conversation databases were patched by the workaround.
Please keep this issue open until a corrected Linux desktop build is available. Posted at the affected user’s request; no private conversation contents, credentials, or raw logs are attached.
ht-Leung commentedon Sep 28, 2026
Additional independent confirmation on Ubuntu 22.04.5 LTS, x86-64, kernel 6.8.0-138-generic, diagnosed and repaired on 2026-09-28.
Affected build:
chatgpt 26.924.22138, bundled app-server0.158.0-alpha.2.1. The installed executable's SHA-256 is23b753552181a8ea661681256c2dbf993fea1285fbc5c824478bad9cbdd45c91.Reproduction and observations
thread/readrequests returned promptly, but the UI remained waiting for resume. Bundled-plugin reconciliation stalled on a child-process dependency.bash,git,ps, andcodexchildren. Shell-environment loading timed out after 5000 ms.0x117d9f78targets the empty function at0x11ce69c8, matching this issue.Workaround and end-to-end verification
A local preload guard preserving the existing SIGCHLD handler resolved the failure with the original installed executable and existing signed-in profile. The guard is restricted to the exact executable hash and verified handler offsets/bytes, is scoped to the desktop launcher, and removes
LD_PRELOADfrom the environment before children are launched.Verified results:
thread/resumerequest completed in 177 ms, with no error.bundled_plugins_reconcile_completedappeared.No system package files, authentication data, or conversation history were deleted or modified by the workaround. Temporary diagnostic copies/profiles were removed. This is a version-specific local workaround, not an upstream fix or a long-duration stability claim.
Please include Linux packaged-app smoke tests for opening existing local history and completing a new conversation, plus startup child-process completion. A bounded failure with a visible error for startup dependencies would also help avoid an indefinite spinner.
Posted with the affected user's authorization; account/session identifiers, private paths, credentials, and conversation contents are omitted.
lovasoa commentedon Sep 28, 2026
I suggest adding a test that launches the app and sends a prompt, and not releasing a new version of the app while that test fails.
mcirsta commentedon Sep 28, 2026
I suggest someone actually testing the app for 5 minutes before releasing if that's not too much to ask.
VirelNode commentedon Sep 28, 2026
I was able to edit within a couple of minutes, but yea I agree.
solankydev commentedon Sep 28, 2026
Update: A new version arrived just a little while ago, and so far the issue seems to be fixed.
yuzhu-oai commentedon Sep 28, 2026
The issue has been fixed. Please update to the latest version.
cylon58 commentedon Oct 4, 2026
Additional confirmation from an Omarchy (Arch Linux) x86-64 installation, investigated on 2026-10-04. This concerns the already-affected build, not a claim that the upstream fix regressed.
Distribution/version detail: the installed
openai-codex-desktoppackage was26.924.22138-1, and the locally configured pacman repository metadata still advertised that version at the time of investigation. The bundled app-server reported0.158.0-alpha.2.1. Kernel:7.2.5-3-omarchy, Wayland. We did not refresh repository metadata during this investigation, so we cannot establish the current state of the remote package mirror.Observed failure:
thread/readandthread/listrequests.ssh -Gprobe timed out after 5000 ms, followed bySSH: codex path probe timed out after 60000ms.ssh,bash,git,ps,gh, andcodex.Controlled version comparison on the same machine:
26.924.2213826.915.31029Both tests used separate
CODEX_HOMEand user-data directories, with headless launches. Returning to26.915.31029with the existing real profile then restored both symptoms: the SSH codex-path probe completed in 675 ms, the remote app-server handshake succeeded, and the user confirmed local chat messages rendered again. No SSH/Tailscale configuration or conversation-history reset was required. No SIGCHLD preload patch was applied.The newer fixed build mentioned above has not been tested on this installation. This adds a version-controlled downgrade comparison and another affected distribution to the existing report. It also highlights that users with stale distribution package metadata can still encounter this after the upstream fix.
Posted with the affected user's authorization. No raw logs, chat contents, credentials, private paths, hostnames, network addresses, or session identifiers are attached.