From 4a106c1acfc43a74be297bd24c1fbe4dd6a5595a Mon Sep 17 00:00:00 2001 From: Chris Henzie Date: Tue, 16 Dec 2025 11:06:48 -0800 Subject: [PATCH 1/2] fix: prevent panic when processing null project items The GraphQL API can return `null` nodes in the `projectItems` connection, causing a runtime panic (nil pointer dereference) when the CLI attempted to access fields on these nil nodes. This crash occurs even with personal access tokens with full read access. Adds a check to safely skip `nil` nodes in `ProjectsV2ItemsForIssue` and `ProjectsV2ItemsForPullRequest`. Signed-off-by: Chris Henzie --- api/queries_projects_v2.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/queries_projects_v2.go b/api/queries_projects_v2.go index 68681f2e869..47ee87c8357 100644 --- a/api/queries_projects_v2.go +++ b/api/queries_projects_v2.go @@ -106,6 +106,9 @@ func ProjectsV2ItemsForIssue(client *Client, repo ghrepo.Interface, issue *Issue return err } for _, projectItemNode := range query.Repository.Issue.ProjectItems.Nodes { + if projectItemNode == nil { + continue + } items.Nodes = append(items.Nodes, &ProjectV2Item{ ID: projectItemNode.ID, Project: ProjectV2ItemProject{ @@ -175,6 +178,9 @@ func ProjectsV2ItemsForPullRequest(client *Client, repo ghrepo.Interface, pr *Pu } for _, projectItemNode := range query.Repository.PullRequest.ProjectItems.Nodes { + if projectItemNode == nil { + continue + } items.Nodes = append(items.Nodes, &ProjectV2Item{ ID: projectItemNode.ID, Project: ProjectV2ItemProject{ From 1117477da2957b1840901b6a11320d51e314752c Mon Sep 17 00:00:00 2001 From: Andy Feller Date: Mon, 22 Dec 2025 10:16:21 -0500 Subject: [PATCH 2/2] Add test to ensure null values are skipped --- api/queries_projects_v2_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/api/queries_projects_v2_test.go b/api/queries_projects_v2_test.go index fae49c9268b..3d29a19c144 100644 --- a/api/queries_projects_v2_test.go +++ b/api/queries_projects_v2_test.go @@ -129,6 +129,17 @@ func TestProjectsV2ItemsForIssue(t *testing.T) { }, expectError: true, }, + { + name: "skips null project items for issue", + httpStubs: func(reg *httpmock.Registry) { + reg.Register( + httpmock.GraphQL(`query IssueProjectItems\b`), + httpmock.GraphQLQuery(`{"data":{"repository":{"issue":{"projectItems":{"totalCount":1,"nodes":[null]}}}}}`, + func(query string, inputs map[string]interface{}) {}), + ) + }, + expectItems: ProjectItems{}, + }, } for _, tt := range tests { @@ -186,6 +197,17 @@ func TestProjectsV2ItemsForPullRequest(t *testing.T) { }, expectError: true, }, + { + name: "skips null project items for pull request", + httpStubs: func(reg *httpmock.Registry) { + reg.Register( + httpmock.GraphQL(`query PullRequestProjectItems\b`), + httpmock.GraphQLQuery(`{"data":{"repository":{"pullRequest":{"projectItems":{"totalCount":1,"nodes":[null]}}}}}`, + func(query string, inputs map[string]interface{}) {}), + ) + }, + expectItems: ProjectItems{}, + }, { name: "retrieves project items that have status columns", httpStubs: func(reg *httpmock.Registry) {