Skip to content

fix: gh aw health always returns "No workflow runs found"#20221

Merged
mnkiefer merged 9 commits intomainfrom
copilot/investigate-gh-aw-health-issue
Mar 9, 2026
Merged

fix: gh aw health always returns "No workflow runs found"#20221
mnkiefer merged 9 commits intomainfrom
copilot/investigate-gh-aw-health-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 9, 2026

gh aw health reported no workflow runs even when runs existed, because run.WorkflowPath was always "", making the .lock.yml filter in fetchWorkflowRuns always false and silently discarding every run.

Root cause

The path field was accidentally dropped from the gh run list --json field list in commit 61cc2d7ac (Jan 4 2026, "Add exit code and stderr logging…"), one day after it had been deliberately added in 8c97bcaa0 (Jan 3 2026, "Fix missing workflow_path field in logs JSON output"). This was a code regression — not a gh version change.

The health command (added Jan 29 2026) relied on WorkflowPath being populated to drive this filter:

if strings.HasSuffix(run.WorkflowPath, ".lock.yml") { // always false — path never fetched
    allRuns = append(allRuns, run)
}

Since path was absent from the query, run.WorkflowPath was always "" and every run was discarded.

Fix

path is restored to the --json field list in listWorkflowRunsWithPagination. Because gh run list outputs the key path while WorkflowRun serialises it as workflowPath (for backward compatibility), the unmarshal step uses a local helper struct to bridge the field name difference before the runs are returned. The .lock.yml filter in fetchWorkflowRuns is preserved as intended.

Regression tests

A new test file pkg/cli/logs_github_api_test.go ensures this cannot recur:

  • TestWorkflowRunPathFieldUnmarshal — verifies the path JSON key is correctly bridged to WorkflowRun.WorkflowPath during unmarshal
  • TestFetchWorkflowRunsLockYMLFilter — verifies the .lock.yml filter includes agentic runs, excludes plain .yml runs, calculates durations, and rejects empty WorkflowPath (the pre-fix state)

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI linked an issue Mar 9, 2026 that may be closed by this pull request
…o health metrics

Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com>
Copilot AI changed the title [WIP] Investigate no health metrics returned in gh aw health command fix: gh aw health always returns "No workflow runs found" Mar 9, 2026
@mnkiefer
Copy link
Copy Markdown
Contributor

mnkiefer commented Mar 9, 2026

@copilot Keep the filter, we only want to see agentic workflows here (.lock.yml), not regular actions workflows (.yml). But investigate why, with the filter in place, this might have been emtpy.

…ter works

Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 9, 2026

@copilot Keep the filter, we only want to see agentic workflows here (.lock.yml), not regular actions workflows (.yml). But investigate why, with the filter in place, this might have...

Restored the filter. The root cause was a code regression, not a gh version change.

Timeline:

  • Jan 3 20268c97bcaa0 deliberately added path to the gh run list --json fields to fix a prior missing-field issue
  • Jan 4 202661cc2d7ac ("Add exit code and stderr logging…") accidentally dropped path from that same field list during an unrelated refactor, silently re-introducing the bug
  • Jan 29 2026af4f4c0d3 added the health command, which relied on WorkflowPath being populated to drive the .lock.yml filter — but by this point path had already been missing for 25 days

Fix (def364a): path is restored to the --json field list in listWorkflowRunsWithPagination. Because gh run list outputs the key path while WorkflowRun serialises it as workflowPath (for backward compatibility), the unmarshal step now uses a local helper struct to bridge the field name difference before the runs are returned.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GO111MODULE x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /usr/bin/git -json GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha /tmp/TestHashConsistency_GoAndJavaScript2645839805/001/test-simple-frontmatter.md erignore /usr/bin/git -json GO111MODULE 64/bin/go git -C /tmp/shared-actions-test2113099901 resolved$ /usr/bin/git remote.origin.urgit GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha -json GO111MODULE (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE tr/ytUgHB2WOGAJoX6mK9KE/Es5JHOhs98SOCpl_QrR0 env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --git-dir node /usr/bin/git run lint:cjs 64/bin/go git conf�� user.name Test User /usr/bin/gh &#34;prettier&#34; --chegit sh 64/bin/go gh (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel x_amd64/vet /usr/bin/git -json GO111MODULE 64/bin/go git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE 64/pkg/tool/linu--show-toplevel git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha /tmp/gh-aw-test-runs/20260309-142136-29525/test-2603232749/.github/workflows rev-parse /usr/bin/git heck &#39;**/*.cjs&#39; git GO111MODULE 64/bin/go git init�� GOMODCACHE go /usr/bin/git ck &#39;scripts/**/*git GO111MODULE 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha k/gh-aw/gh-aw/pkg/stringutil/ansi.go k/gh-aw/gh-aw/pkg/stringutil/identifiers.go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/compile remote.origin.urgit GO111MODULE 64/bin/go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/compile -o /tmp/go-build1832692545/b421/_pkg_.a -trimpath /opt/hostedtoolcache/node/24.14.0/x64/bin/node -p github.com/githurev-parse -lang=go1.25 node (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel go /usr/bin/git 2339256098/.githgit GO111MODULE x_amd64/compile git rev-�� --show-toplevel x_amd64/compile /usr/bin/git -json GO111MODULE ache/go/1.25.0/x--show-toplevel git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE ortcfg k/gh�� g/testutil/tempdGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD erignore ache/go/1.25.0/xGO111MODULE (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -c=4 -nolocalimports -importcfg /tmp/go-build1832692545/b374/importcfg -pack /home/REDACTED/work/gh-aw/gh-aw/pkg/cli/access_log.go /home/REDACTED/work/gh-aw/gh-aw/pkg/cli/actionlint.go env e=false GO111MODULE 64/bin/go GOINSECURE %H %ct %D ac1ca9a1b2792560/tmp/go-build1832692545/b389/_pkg_.a go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha ripts/lint_errorGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/xGO111MODULE env 4742461/b385/_pkGOINSECURE GO111MODULE 64/bin/go GOINSECURE bagabas/go-udiff-atomic GOMODCACHE go (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha /tmp/gh-aw-test-runs/20260309-142136-29525/test-2603232749/.github/workflows rev-parse /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet heck &#39;**/*.cjs&#39; git GO111MODULE 64/bin/go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -ato�� -bool -buildtags /usr/bin/git -errorsas -ifaceassert -nilfunc git (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha /tmp/gh-aw-test-runs/20260309-142136-29525/test-2603232749/.github/workflows rev-parse /usr/bin/gh heck &#39;**/*.cjs&#39; git GO111MODULE 64/bin/go gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha edcfg GO111MODULE ache/go/1.25.0/x64/pkg/tool/linu-nilfunc GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/x64/pkg/tool/linu-tests env 2692545/b412/_pkg_.a GO111MODULE 2692545/b412=&gt; GOINSECURE b/gh-aw/pkg/reporev-parse GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE wJ/GFtmVa307QDDNuUCuh0B/-q2laYTOponvNzHYgi3f (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go estl�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE uR/06fD-SCH0ioFmtMaFokJ/R7zSKdIMkKk_km7pr_Of (http block)
  • https://api.github.com/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go ache�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha to pkg/workflow/data/action_pins-p GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 1122961498/.github/workflows GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq .object.sha ck &#39;scripts/**/*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v2.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE node (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v3.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh (http block)
  • https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 2603232749/.github/workflows GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/nonexistent/repo/actions/runs/12345
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE go estl�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/owner/repo/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE go env ck &#39;scripts/**/*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/owner/repo/contents/file.md
    • Triggering command: /tmp/go-build1832692545/b383/cli.test /tmp/go-build1832692545/b383/cli.test -test.testlogfile=/tmp/go-build1832692545/b383/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD GOMODCACHE ortcfg env om/charmbraceletGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/xGO111MODULE (http block)
  • https://api.github.com/repos/test-owner/test-repo/actions/secrets
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go k/gh�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD erignore go (http block)

If you need me to access, download, or install something from one of these locations, you can either:

@mnkiefer
Copy link
Copy Markdown
Contributor

mnkiefer commented Mar 9, 2026

@copilot Add tests to ensure this cannot happen again.

… JSON query

Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 9, 2026

@copilot Add tests to ensure this cannot happen again.

Added in commit 1df41c0 — new test file pkg/cli/logs_github_api_test.go with four regression tests:

  • TestWorkflowRunJSONFieldsContainsPath — fails immediately if path is dropped from the workflowRunJSONFields constant (the exact regression vector)
  • TestWorkflowRunJSONFieldsAllPresent — belt-and-braces: verifies all required gh run list field names are in the constant
  • TestWorkflowRunPathFieldUnmarshal — verifies that the path JSON key is correctly bridged to WorkflowRun.WorkflowPath during unmarshal
  • TestFetchWorkflowRunsLockYMLFilter — verifies the .lock.yml filter includes agentic runs, excludes .yml runs, and rejects empty WorkflowPath (the pre-fix state)

The JSON fields string was also extracted to the named constant workflowRunJSONFields (with a comment explaining the path dependency) so the tests have a single stable target.

@mnkiefer
Copy link
Copy Markdown
Contributor

mnkiefer commented Mar 9, 2026

@copilot Only keep fix the string that was missing "path" . Keep changes to the code minimal.

mnkiefer and others added 2 commits March 9, 2026 18:15
…WorkflowPath bridge and .lock.yml filter

Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 9, 2026

@copilot Only keep fix the string that was missing "path" . Keep changes to the code minimal.

Done in 31f3bca. The extracted constant has been removed — production code is back to a single inline string with path restored. The two tests that depended on the constant are gone; the two behaviour-focused tests remain (TestWorkflowRunPathFieldUnmarshal and TestFetchWorkflowRunsLockYMLFilter).

@mnkiefer mnkiefer marked this pull request as ready for review March 9, 2026 17:17
Copilot AI review requested due to automatic review settings March 9, 2026 17:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a regression where gh aw health always reported "No workflow runs found" because the path field was accidentally dropped from the gh run list --json query. The WorkflowPath field on WorkflowRun was always empty, causing the .lock.yml suffix filter in fetchWorkflowRuns to discard every run.

Changes:

  • Restores path to the --json field list in listWorkflowRunsWithPagination and adds an unmarshal bridge to map the path JSON key to WorkflowRun.WorkflowPath (which uses the workflowPath JSON tag).
  • Adds a new test file with two regression tests: one verifying the JSON unmarshal bridge and one verifying the .lock.yml filter logic.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
pkg/cli/logs_github_api.go Adds path back to the --json field list and uses a helper struct during unmarshal to bridge the pathWorkflowPath field name mismatch.
pkg/cli/logs_github_api_test.go New test file with regression tests for the path field unmarshal and the .lock.yml filter logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mnkiefer mnkiefer merged commit 81e2556 into main Mar 9, 2026
84 checks passed
@mnkiefer mnkiefer deleted the copilot/investigate-gh-aw-health-issue branch March 9, 2026 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No health metrics returned

3 participants