Skip to content

Remove-GitHubWorkflowRun does not delete all piped workflow runs #571

@MariusStorhaug

Description

Context

Remove-GitHubWorkflowRun accepts pipeline input from Get-GitHubWorkflowRun via ValueFromPipelineByPropertyName
on the Owner, Repository, and ID parameters. This enables a common bulk-deletion pattern:

Get-GitHubWorkflowRun -Owner PSModule -Repository GitHub |
    Where-Object { $_.Status -ne 'in_progress' } |
    Remove-GitHubWorkflowRun

Request

When piping workflow runs from Get-GitHubWorkflowRun through Where-Object into Remove-GitHubWorkflowRun,
only some runs are deleted — not all matching runs. Running the same Get-GitHubWorkflowRun pipeline
afterward still returns runs that should have been removed.

Reproduction steps

# Step 1: Delete all non-in-progress workflow runs
Get-GitHubWorkflowRun -Owner PSModule -Repository GitHub |
    Where-Object { $_.Status -ne 'in_progress' } |
    Remove-GitHubWorkflowRun
# Answer "A" (Yes to All) at confirmation prompt

# Step 2: Verify — expect no results
Get-GitHubWorkflowRun -Owner PSModule -Repository GitHub |
    Where-Object { $_.Status -ne 'in_progress' }
# ACTUAL: Still returns workflow runs that should have been deleted

Observed behavior

The confirmation prompt appeared for only one run (23967646592). After answering "Yes to All",
the command completed. Running the second command still returned 15 workflow runs — all from weeks earlier
(February 2026) — that should have been fed through the pipeline and deleted:

Terminal output
Confirm
Are you sure you want to perform this action?
Performing the operation "Delete workflow run" on target "PSModule/GitHub/23967646592".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): a
State Name                          ID          Owner    Repository CreatedAt           UpdatedAt
----- ----                          --          -----    ---------- ---------           ---------
⛔​    Process-PSModule              22281865302 PSModule GitHub     22.02.2026 17:29:19 22.02.2026 18:59:44
✅​    PR #561                       22281864810 PSModule GitHub     22.02.2026 17:29:16 22.02.2026 17:30:06
✅​    Running Copilot coding agent  22281843433 PSModule GitHub     22.02.2026 17:27:51 22.02.2026 17:29:46
✅​    PR #561                       22281843002 PSModule GitHub     22.02.2026 17:27:49 22.02.2026 17:28:37
✅​    Process-PSModule              22275476744 PSModule GitHub     22.02.2026 10:35:26 22.02.2026 15:29:38
✅​    Push on main                  22275476513 PSModule GitHub     22.02.2026 10:35:25 22.02.2026 10:36:08
❌​    Process-PSModule              22267507645 PSModule GitHub     22.02.2026 00:47:32 22.02.2026 03:25:09
✅​    Process-PSModule              22253968767 PSModule GitHub     21.02.2026 08:56:17 21.02.2026 12:37:16
❌​    Process-PSModule              22246824677 PSModule GitHub     21.02.2026 00:43:47 21.02.2026 03:19:29
✅​    Process-PSModule              22216586521 PSModule GitHub     20.02.2026 08:15:44 20.02.2026 22:01:32
✅​    PR #555                       22216585539 PSModule GitHub     20.02.2026 08:15:42 20.02.2026 08:16:33
✅​    Addressing comment on PR #555 22216537392 PSModule GitHub     20.02.2026 08:14:00 20.02.2026 08:17:03
❌​    Process-PSModule              22206472365 PSModule GitHub     20.02.2026 00:44:16 20.02.2026 03:15:28
❌​    Process-PSModule              22199781665 PSModule GitHub     19.02.2026 20:56:49 19.02.2026 23:33:37
✅​    PR #555                       22199779468 PSModule GitHub     19.02.2026 20:56:46 19.02.2026 20:57:49

The deleted run (23967646592) does not appear in the subsequent listing, confirming that at least one deletion
succeeded. However, runs from February 2026 — weeks old and clearly not in_progress — were not deleted.

What is expected

All workflow runs that match the pipeline filter should be deleted. After the pipeline completes, re-running
the same Get-GitHubWorkflowRun query with the same filter should return no results (assuming no new runs
were created in the interim).

Acceptance criteria

  • All workflow runs flowing through the pipeline are processed by Remove-GitHubWorkflowRun
  • No silent failures — if a deletion fails, an error is surfaced
  • Bulk deletion via pipeline works end-to-end without partial results

Technical decisions

Investigation is needed to determine the root cause. The following areas are the most likely candidates:

Possible cause 1 — Pagination in Get-GitHubWorkflowRun: The GitHub REST API
lists workflow runs
with paginated results. Invoke-GitHubAPI follows rel="next" link headers to fetch all pages.
However, the response wraps runs inside workflow_runs — each page yields
$_.Response.workflow_runs. If only the first page's runs are emitted before the pipeline
starts consuming, and a deletion error terminates the pipeline, subsequent pages would never be fetched.
A terminating error on any single DELETE call (e.g., 409 Conflict for a run in a protected state)
would kill the pipeline and prevent remaining items — including later pages — from being processed.

Possible cause 2 — Silent API errors during deletion: Remove-GitHubWorkflowRun calls
$null = Invoke-GitHubAPI @apiParams and discards the result. If the API returns a non-success
status code for certain runs (e.g., runs associated with a required status check, or runs still in a
transitional state), and Invoke-GitHubAPI throws a terminating error, the pipeline would be
interrupted and remaining items would not be processed. No error output would be visible if the
exception is swallowed or if the pipeline simply stops.

Possible cause 3 — $_ vs $Object in GitHubWorkflowRun constructor: The
constructor
mixes $_ (automatic variable from calling scope) with $Object (the constructor parameter).
Most properties use $_ instead of $Object:

GitHubWorkflowRun([PSCustomObject] $Object) {
    $this.ID = $_.id              # Uses $_
    $this.NodeID = $_.node_id     # Uses $_
    $this.Name = $_.name          # Uses $_
    $this.Owner = [GitHubOwner]::new($Object.repository.owner)   # Uses $Object
    $this.Repository = [GitHubRepository]::new($Object.repository) # Uses $Object
    # ... remaining properties all use $_ ...
}

This works by coincidence when called from ForEach-Object { [GitHubWorkflowRun]::new($_) }
because $_ from the calling scope leaks into the class constructor in PowerShell. However, this
is fragile and could break across PowerShell versions or in contexts where $_ is not set.

Diagnostic approach: Add -Verbose and -Debug to the pipeline, count objects at each stage,
and check for thrown errors using -ErrorAction Stop or try/catch around the pipeline to
determine where items are lost.


Implementation plan

Diagnosis

  • Reproduce the issue with -Verbose and -ErrorVariable to capture any hidden errors
  • Count objects emitted by Get-GitHubWorkflowRun, passed by Where-Object, and received by Remove-GitHubWorkflowRun to identify where items are lost
  • Check if Invoke-GitHubAPI throws terminating errors on DELETE failures that would kill the pipeline

Fix — GitHubWorkflowRun constructor

  • Replace all $_ references with $Object in the GitHubWorkflowRun constructor in src/classes/public/Workflows/GitHubWorkflowRun.ps1

Fix — Error handling in Remove-GitHubWorkflowRun

  • Wrap the Invoke-GitHubAPI call in Remove-GitHubWorkflowRun with error handling that writes a non-terminating error instead of allowing a terminating error to kill the pipeline
  • Ensure the error message includes the run ID so the user knows which deletion failed

Tests

  • Add test verifying pipeline input from Get-GitHubWorkflowRun output processes all items
  • Add test verifying that a failed deletion does not terminate the pipeline for remaining items

Metadata

Metadata

Labels

bugSomething isn't workingpatch

Type

Projects

Status

Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions