Auto-Close Sub-Issues When Parent Issue Is Closed
GitHub introduced sub-issues at the beginning of 2025, allowing users to break down large issues into smaller, more manageable tasks. This hierarchy makes it easier to track progress and organize work, especially for complex projects.
In our organization, we actively use this feature. However, we found it repetitive to manually close each sub-issue once the parent issue is completed.
To streamline this, we automated the process: when a parent issue is closed, a GitHub Actions workflow automatically closes all of its sub-issues.
Here’s how we did it
GitHub Workflow: Close Sub-Issues Automatically
This GitHub Actions workflow listens for the issues.closed
event and performs the following:
- Fetches all sub-issues of the closed parent.
- Closes each sub-issue.
- Comments on the parent issue summarizing the action.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
name: Close Sub-Issues on Parent Close
on:
issues:
types: [closed]
permissions:
issues: write
jobs:
close_sub_issues:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Get Sub-Issues
id: get_sub_issues
env:
GITHUB_TOKEN: $
run: |
sudo apt-get update && sudo apt-get install -y jq curl
page=1
sub_issues=()
while :; do
response=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$/issues/$/sub_issues?page=$page")
if [ "$(echo "$response" | jq length)" -eq 0 ]; then
echo "No more sub-issues found on page $page."
break
fi
new_sub_issues=$(echo "$response" | jq -r '.[] | select(.number) | .number')
if [ -z "$new_sub_issues" ]; then
echo "No sub-issues found on page $page."
break
fi
for issue in $new_sub_issues; do
sub_issues+=("$issue")
done
((page++))
done
if [ ${#sub_issues[@]} -eq 0 ]; then
echo "No sub-issues found."
echo "HAS_SUB_ISSUES=false" >> "$GITHUB_ENV"
else
echo "Sub-issues found: ${sub_issues[*]}"
echo "SUB_ISSUES<<EOF" >> "$GITHUB_ENV"
printf "%s " "${sub_issues[@]}" >> "$GITHUB_ENV"
echo "" >> "$GITHUB_ENV"
echo "EOF" >> "$GITHUB_ENV"
echo "HAS_SUB_ISSUES=true" >> "$GITHUB_ENV"
fi
- name: Close Sub-Issues
if: env.HAS_SUB_ISSUES == 'true'
env:
GITHUB_TOKEN: $
run: |
closed_issues=""
for issue_number in $SUB_ISSUES; do
echo "Closing sub-issue #$issue_number..."
response=$(curl -s -w "\n%{http_code}" -X PATCH -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-d '{"state": "closed"}' \
"https://api.github.com/repos/$/issues/$issue_number")
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
if [ "$http_code" -eq 200 ]; then
echo "Sub-issue #$issue_number closed successfully."
closed_issues="$closed_issues #$issue_number"
else
echo "Failed to close sub-issue #$issue_number (HTTP $http_code): $body"
fi
done
echo "CLOSED_ISSUES<<EOF" >> "$GITHUB_ENV"
echo "$closed_issues" >> "$GITHUB_ENV"
echo "EOF" >> "$GITHUB_ENV"
- name: Comment on Parent Issue
if: env.HAS_SUB_ISSUES == 'true' && env.CLOSED_ISSUES != ''
env:
GITHUB_TOKEN: $
run: |
if [ -n "$CLOSED_ISSUES" ]; then
body="âś… Automatically closed the following sub-issues:$CLOSED_ISSUES"
curl -s -X POST -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-d "$(jq -nc --arg body "$body" '{"body": $body}')" \
"https://api.github.com/repos/$/issues/$/comments"
fi
How to Use It
Create a new workflow file
In your repository, create a new file under.github/workflows/
, for example:.github/workflows/close-sub-issues.yml
Paste the workflow code
Copy and paste the full workflow YAML content into this file.Commit the file
Commit and push it to your repository.
Now, whenever a parent issue is closed, all of its sub-issues will automatically be closed as well.
Limitations and Investigation
Notable limitation of this GitHub Actions workflow is the requirement of a runner for every job, even if the task is lightweight and only involves making API calls.
In Azure DevOps, we often use agentless jobs (via pool: server
) to handle such orchestration tasks—like approvals, REST API calls without consuming a runner or compute resources.
Unfortunately, GitHub Actions does not currently support agentless jobs. This means:
- A runner must be provisioned and spun up even for simple API operations.
- This consumes workflow minutes, even for non-compute-heavy tasks.
We’ve raised a feature request with GitHub to support agentless jobs for such scenarios: GitHub Community Discussion #159471
We hope GitHub considers adding this feature to improve cost-efficiency and better align with other CI/CD platforms.