Skip to content

Wrapper reports signal-based child termination as exit code 0 #17978

Closed

Description

@davifernan

Description

When the Node wrapper in packages/opencode/bin/opencode launches a child that terminates via signal, it can report exit code 0.

The current wrapper does this:

const code = typeof result.status === "number" ? result.status : 0
process.exit(code)

For spawnSync, result.status is null and result.signal is set when the child terminates via signal. That makes an abnormal termination look like a clean exit to supervisors and scripts.

This is related to #17854, #15558, and #2489, but it is a different path. Those issues are about opencode run returning 0 for application-level failures. This issue is specifically about the outer wrapper converting signal-based child termination into 0 before the caller ever sees the real signal.

Plugins

No response

OpenCode version

1.2.27 (also reproducible on current dev)

Steps to reproduce

  1. Run:
    node -e 'const cp=require("child_process"); const r=cp.spawnSync(process.env.SHELL||"bash",["-lc","kill -TERM $$"],{stdio:"inherit"}); console.log({status:r.status, signal:r.signal})'
  2. Observe that spawnSync reports status: null and a non-null signal when the child dies from a signal.
  3. Compare that with the current wrapper logic in packages/opencode/bin/opencode, which maps the same case to exit code 0.
  4. Expected: the wrapper should preserve the signal or at least exit non-zero.

Screenshot and/or share link

No response

Operating System

macOS 15.5 arm64

Terminal

Ghostty

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Mar 17, 2026
  2. github-actions commented on Mar 17, 2026

    @github-actions
    Contributor

    This issue doesn't fully meet our contributing guidelines.

    What needs to be fixed:

    • No issue template was used. Please use one of the three required templates: Bug Report, Feature Request, or Question. The bug report template requires fields like OpenCode version, OS, terminal, and steps to reproduce.

    Please edit this issue to address the above within 2 hours, or it will be automatically closed.


    This issue might be a duplicate of existing issues. Please check:

    • Error returns exit code 0 #17854: Also reports exit code 0 returned on errors/abnormal conditions (though that issue covers application-level errors rather than signal-based child termination specifically)

    If you believe this was flagged incorrectly, please let a maintainer know.

  3. added
    needs:complianceThis means the issue will auto-close after 2 hours.
    and removed
    needs:complianceThis means the issue will auto-close after 2 hours.
    on Mar 17, 2026
  4. github-actions commented on Mar 17, 2026

    @github-actions
    Contributor

    Thank you for updating the issue! It now includes all the required information — a clear description, steps to reproduce, version, OS, and terminal. The compliance label has been removed.

  5. removed
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  6. chubes4 commented on May 8, 2026

    @chubes4
    Contributor

    I opened a PR that fixes this wrapper path as part of the same root cause: #26259

    The current wrapper has two related signal bugs:

    1. It uses blocking spawnSync(), so the wrapper cannot forward SIGTERM/SIGINT/SIGHUP while the child is running. If a supervisor kills the wrapper, the real .opencode child can survive and become a PID-1 orphan.
    2. As this issue notes, spawnSync() reports signal exits as status: null with signal set, and the wrapper currently maps that to exit code 0.

    The PR switches to async spawn(), forwards standard termination signals to the child, and when the child exits due to a signal, re-raises that signal on the wrapper process instead of converting it to 0.

    Verification:

    Case Homeboy run Result
    Stock upstream wrapper 8d26c4f6-4e90-459b-a15d-49e76cc0f9da 3/3 orphans
    Patched wrapper from PR #26259 bdc45e95-2ec3-44bf-b50a-c7daee37552e 0/3 orphans

    Signals tested: SIGTERM, SIGINT, SIGHUP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions