Describe the bug
In GitHub Copilot CLI 1.0.88 on Linux, a userPromptSubmitted command hook can finish successfully in milliseconds, but Copilot does not recognize its completion until the configured timeout expires and the thread waiting for child process completion is woken up.
Starting copilot using "COPILOT_SETUP_TERMINAL=false copilot" avoid the issue.
We traced this to a process-wide SIGCHLD handler conflict between Copilot’s in-process native runtime and Node.js/libuv:
- The native runtime installs a SIGCHLD handler.
- Automatic terminal-setup detection invokes Node’s child_process.exec to run:
ps -Ao pid=,ppid=,comm=
- libuv’s uv_spawn replaces the native runtime’s SIGCHLD handler.
- After that subprocess completes, libuv cleanup through uv_signal_stop resets SIGCHLD to SIG_DFL , rather than restoring the native runtime’s handler.
- A subsequently launched prompt-hook process exits successfully, but its completion does not promptly wake the native runtime’s child waiter.
- Copilot collects the already-available exit status at our configured 300-second boundary for our hook processor and continues normally.
This is not a hook script taking five minutes to execute, nor a slow model response.
Environment
• GitHub Copilot CLI: 1.0.88
• Node.js version reported by CLI: v24.20.0
• Copilot runs on a remote Linux host.
• Two users connected to the same Linux host using the same remote account, through SSH:
• An SSH session from macOS consistently received fast responses with SSH sessions established using iTerm on the Mac.
• An SSH session from Windows reproduced the delay when using mobaxterm or putty.
• The configured UserPromptSubmit command hook had a 300-second timeout.
• The hook was loaded from the user-level hook configuration.
In the affected session:
• Copilot emits hook.start for userPromptSubmitted .
• The hook process exits with status 0 in approximately 274 ms.
• SIGCHLD is delivered to the parent, but no corresponding signal handler runs.
• The child remains a zombie, parented to Copilot.
• Copilot remains active, but the prompt does not progress to a model request.
• Approximately 300 seconds after hook start (our set timeout), Copilot calls wait4 again and collects the successful exit status.
• Copilot then emits hook.end with success: true and proceeds to the model.
Affected version
1.0.88
Steps to reproduce the behavior
- Configure a user-level UserPromptSubmit command hook with a 300-second timeout.
- Start interactive Copilot CLI 1.0.88 on Linux from the affected Windows-origin SSH session.
- Submit a simple text prompt that does not require a tool call.
- Observe hook.start , but no timely hook.end or model response.
- Inspect the hook child: it has already exited and remains a zombie.
- Wait for the configured timeout boundary; Copilot recognizes the successful exit and responds.
Control tests:
• Removing the user-level hooks eliminated the prompt delay.
• With hooks enabled, the macOS-origin SSH session responded promptly.
• In the fast capture, the native runtime’s SIGCHLD handler remained effective and the hook child was reaped immediately.
• In the delayed capture, the terminal-detection ps subprocess ran and the parent’s SIGCHLD handler was subsequently reset to default.
Use this strace command to see the replacement of the SIGCHLD handler for
strace -ff -k -ttt -T
-e trace=%process,%signal
-e signal=all
-o /tmp/copilot-startup-stack-affected
copilot --log-level debug
Expected behavior
After a userPromptSubmitted hook process exits, Copilot should promptly collect its exit status, emit hook.end , and proceed with the model turn.
Startup subprocesses launched through Node/libuv should not leave the native runtime’s child-exit notification mechanism disabled.
Additional context
No response
Describe the bug
In GitHub Copilot CLI 1.0.88 on Linux, a userPromptSubmitted command hook can finish successfully in milliseconds, but Copilot does not recognize its completion until the configured timeout expires and the thread waiting for child process completion is woken up.
Starting copilot using "COPILOT_SETUP_TERMINAL=false copilot" avoid the issue.
We traced this to a process-wide SIGCHLD handler conflict between Copilot’s in-process native runtime and Node.js/libuv:
ps -Ao pid=,ppid=,comm=
This is not a hook script taking five minutes to execute, nor a slow model response.
Environment
• GitHub Copilot CLI: 1.0.88
• Node.js version reported by CLI: v24.20.0
• Copilot runs on a remote Linux host.
• Two users connected to the same Linux host using the same remote account, through SSH:
• An SSH session from macOS consistently received fast responses with SSH sessions established using iTerm on the Mac.
• An SSH session from Windows reproduced the delay when using mobaxterm or putty.
• The configured UserPromptSubmit command hook had a 300-second timeout.
• The hook was loaded from the user-level hook configuration.
In the affected session:
• Copilot emits hook.start for userPromptSubmitted .
• The hook process exits with status 0 in approximately 274 ms.
• SIGCHLD is delivered to the parent, but no corresponding signal handler runs.
• The child remains a zombie, parented to Copilot.
• Copilot remains active, but the prompt does not progress to a model request.
• Approximately 300 seconds after hook start (our set timeout), Copilot calls wait4 again and collects the successful exit status.
• Copilot then emits hook.end with success: true and proceeds to the model.
Affected version
1.0.88
Steps to reproduce the behavior
Control tests:
• Removing the user-level hooks eliminated the prompt delay.
• With hooks enabled, the macOS-origin SSH session responded promptly.
• In the fast capture, the native runtime’s SIGCHLD handler remained effective and the hook child was reaped immediately.
• In the delayed capture, the terminal-detection ps subprocess ran and the parent’s SIGCHLD handler was subsequently reset to default.
Use this strace command to see the replacement of the SIGCHLD handler for
strace -ff -k -ttt -T
-e trace=%process,%signal
-e signal=all
-o /tmp/copilot-startup-stack-affected
copilot --log-level debug
Expected behavior
After a userPromptSubmitted hook process exits, Copilot should promptly collect its exit status, emit hook.end , and proceed with the model turn.
Startup subprocesses launched through Node/libuv should not leave the native runtime’s child-exit notification mechanism disabled.
Additional context
No response