Skip to content

[Breaking change] Make Process.Run* kill the entire process tree on timeout or cancellation #136466

Description

@adamsitnik

Problem

The .NET 11 System.Diagnostics.Process.Run* convenience methods kill only the immediate child process on timeout or cancellation. Descendants started by that child can remain running.

This matters when launching shells, scripts, build tools, or other programs that spawn subprocesses. Timing out or canceling the operation can leave work running in the background, consuming resources or holding files and redirected standard-stream handles open.

For example, if the launched process starts a long-running child, timing out Process.RunAndCaptureText(...) can terminate the launched process without terminating that child.

The helpers do not provide a way to request whole-process-tree cleanup. Callers needing it must abandon the convenience methods and manually combine Process.Start, output capture, timeout accounting, exit waiting, and Kill(entireProcessTree: true).

The current capture implementation uses parameterless process.Kill() on capture failure and delegates post-capture timeouts to a single-process handle wait:
synchronous implementation,
asynchronous implementation.

Proposed change

Make all Process.Run* methods always kill the entire launched process tree on timeout or cancellation, rather than only the immediate child:

  • Process.Run (all overloads)
  • Process.RunAsync (all overloads)
  • Process.RunAndCaptureText (all overloads)
  • Process.RunAndCaptureTextAsync (all overloads)

Apply this consistently whether timeout/cancellation occurs during output capture or while waiting for process termination. Preserve the existing timeout/cancellation reporting semantics and normal-completion behavior.

This should be the default behavior, without requiring another opt-in flag.

Breaking-change impact

This is an intentional behavioral breaking change: descendants that previously survived a timeout or cancellation would now be terminated.

Callers that intentionally need descendants to survive should use the lower-level Process.Start APIs and manage their lifecycle explicitly.

Note

This issue was drafted with GitHub Copilot.

Activity

  1. dotnet-policy-service commented on Oct 26, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @dotnet/area-system-diagnostics-process
    See info in area-owners.md if you want to be subscribed.

  2. removed
    untriagedNew issue has not been triaged by the area owner
    on Oct 26, 2026
  3. added this to the 12.0.0 milestone on Oct 26, 2026
  4. adamsitnik commented on Oct 26, 2026

    @adamsitnik
    MemberAuthor

    Note from human: both Run and RunAsync use only SafeProcessHandle, which lacks the Kill(entireProcessTree: true) overload. It would be nice to have the best of both words: keep using SPH but also extend it.

  5. changed the title [-][Breaking change proposal] Make Process.Run* kill the entire process tree on timeout or cancellation[/-] [+][Breaking change] Make Process.Run* kill the entire process tree on timeout or cancellation[/+] on Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions