Repository navigation
ocx init busy-loops at ~100% CPU after piped stdin reaches EOF #754
Description
Client or integration
Other — ocx CLI directly
Area
CLI
Summary
Running the interactive ocx init command with finite piped stdin left its bundled Bun process alive and consuming approximately 99% CPU after stdin reached EOF.
The process remained alive for nearly 13 hours. The unrelated OpenCodex background proxy remained healthy and used normal CPU. Even if piped/non-interactive use is unsupported, ocx init should complete, report EOF/non-TTY input as an error, or exit; it should not busy-loop indefinitely.
Reproduction
The incident was triggered with:
printf '1\n\n\nn\n' | ocx initObserved steps:
- Run the command above with OpenCodex 2.7.43.
- Allow the finite input pipe to reach EOF.
- Inspect the surviving process tree with
ps. - Observe that the Bun child remains runnable at approximately 99% CPU instead of exiting.
The surviving process tree was:
/bin/zsh -c printf ... | ocx init
node .../bin/ocx init
bun.exe .../src/cli/index.ts init
For an isolated test that avoids injecting into Codex, use a temporary OpenCodex home and explicit "no" answers:
ocx_tmp="$(mktemp -d)"
printf '1\n\nn\nn\n' | OPENCODEX_HOME="$ocx_tmp" ocx initI have not rerun the isolated command after discovering the incident because the original process evidence already establishes the indefinite high-CPU failure and an uncontrolled retry could create another busy-looping process.
Expected behavior: consume the answers and complete, exit nonzero with a useful EOF message, or reject non-TTY input immediately.
Actual behavior: the Bun initializer survived EOF and continuously consumed one CPU core until killed manually.
Version
2.7.43 (@bitkyc08/opencodex), bundled Bun 1.3.14, Node launcher 20.19.5
Operating system
macOS 26.5.1 (25F80), Apple Silicon / ARM64
Provider and model
Not provider-specific. The initializer selected the first/default ChatGPT-forward provider entry.
Logs or error output
PID PPID %CPU ELAPSED COMMAND
63100 1 0.0 12:55:45 /bin/zsh -c printf ... | ocx init
63102 63100 0.0 12:55:45 node .../bin/ocx init
63103 63102 98.9 12:55:45 bun.exe .../src/cli/index.ts init
Additional observations:
- The Bun initializer had no open network sockets.
- File descriptors 0, 1, and 2 were connected only to pipes.
- A two-second macOS
sampleshowed the main Bun thread continuously active/runnable in its event-loop/readline path. - The separate
ocx start --port 10100service process remained healthy.
Possible code area: src/cli/init.ts creates one readline.Interface, implements prompts with rl.question(), has no explicit pending-question EOF/close handling, and reaches prompt.close() only through normal completion. The sample was unsymbolicated, so this is a suspected area rather than a claimed definitive root cause.
Suggested safeguards:
- Handle readline
close/EOF and settle any pending prompt. - Put
prompt.close()in afinallyblock. - Explicitly reject non-TTY
ocx initruns or queue piped lines safely. - Add a finite-piped-input regression test with a short timeout.
Screenshots and supporting files
A macOS process sample was captured locally. Its relevant result is summarized above; it contains local filesystem paths, so it has not been attached publicly.
Redacted configuration
{
"providerSpecific": false,
"command": "ocx init"
}Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
github-actions commentedon Jul 30, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
github-actions commentedon Jul 30, 2026
Automated translation bookkeeping — detected language: unknown.
Wibias commentedon Jul 30, 2026
[shipping-github] Research review
Claim:
ocx initwith finite piped stdin busy-loops at ~100% CPU after EOF instead of exiting.Checked against: dev@be177ea5
src/cli/init.tsreadlineask()has noclose/EOF handler;prompt.close()only on normal completionEvidence:
createPrompt()insrc/cli/init.tsresolvesrl.questionwithout listening forclose; matches reporter analysis. Reopened after quality-bot auto-close once template filled.Gaps: Did not re-run the piped
printf | ocx initrepro here (would risk a hung process).Wibias commentedon Jul 30, 2026
[shipping-github] Opened PR #774 to address this.
fix(cli): exit ocx init cleanly on piped stdin EOF (#754)
lidge-jun commentedon Jul 31, 2026
Fixed on
dev(verified atbf9bc1ac8), landed inbfa1a599c.ocx initno longer spins after piped stdin reaches EOF.src/cli/init.ts:9-32now tracks the readlinecloseevent and rejects any prompt that is already pending or newly issued after the stream closed, instead of leaving an unresolved promise for the event loop to spin on.:213-223maps that rejection to exit code 1 and closes the interface on every path.Verified the specific failure mode rather than just the file: the pending-question promise is what used to survive EOF, and it is now settled.
Closing. Thanks for the report — a busy-loop pinning a core is the kind of thing that is easy to miss in interactive testing.
docs(plan): disposition all 41 open issues against dev head
fix(cli): exit ocx init cleanly on piped stdin EOF (lidge-jun#754)
docs(plan): disposition all 41 open issues against dev head