github / github/gh-stack

Stack view shows "not ready" / "unable to merge as a stack" on approved mergeable PRs (stale stack UI cache)

Open
#450 3 comments 0 reactions 0 assignees View on GitHub
bug topic: mergeability
Dominant language
Go
Stars
1.5k
Forks
70
Avg merge
1d 8h
Merged PRs (30d)
7

Description

## Summary

The GitHub stack view (native stack feature, not CLI) shows "not ready" on some PRs in a 13-level stack, and displays "unable to merge as a stack" globally, even though every PR in the stack reports `mergeable=MERGEABLE`, `mergeStateStatus=CLEAN` (or `UNSTABLE`), `reviewDecision=APPROVED`, and all status checks passing via both REST and GraphQL APIs.

## Stack structure (anonymized)

```
base-branch
└── feat/base → PR #1 (base: base-branch) ← trunk base
└── feat/layer-2 → PR #2 (base: feat/base)
└── feat/layer-3 → PR #3 (base: feat/layer-2)
└── feat/layer-4 → PR #4 (base: feat/layer-3)
└── feat/layer-5 → PR #5 (base: feat/layer-4)
└── feat/layer-6 → PR #6 (base: feat/layer-5)
└── feat/layer-7 → PR #7 (base: feat/layer-6)
└── feat/layer-8 → PR #8 (base: feat/layer-7)
└── feat/layer-9 → PR #9 (base: feat/layer-8)
└── feat/layer-A → PR #10 (base: feat/layer-9)
└── feat/layer-B → PR #11 (base: feat/layer-A)
└── feat/layer-C → PR #12 (base: feat/layer-B)
└── feat/layer-D → PR #13 (base: feat/layer-C)
```

13 PRs in total. The bottom PR targets `base-branch`; each subsequent PR targets its predecessor's branch. All PRs are open, non-draft, created via `gh stack submit`.

## Environment

- `gh` 2.97.0
- `gh-stack` v0.1.0
- Repository: private, no branch protection, no repository rulesets, no merge queue, no CODEOWNERS.
- "Dismiss stale pull request approvals when new commits are pushed": disabled.

## Observed behavior

### In the GitHub stack UI (native stack view)

- Bottom 7 PRs (#1–#7): show **"Ready"**
- PR #8: shows **"Not ready"** (no tooltip / reason shown)
- PR #9: shows **"Blocked downstack"**
- PR #10: shows **"Not ready"** (no tooltip / reason shown)
- PRs #11–#13: show **"Blocked downstack"**
- At the top: global message **"Unable to merge as a stack"**

### Via the API (both REST and GraphQL, confirmed multiple times over several minutes)

Every PR in the stack (including #8 and #10) consistently reports:

| Field | Value |
|---|---|
| `mergeable` | `MERGEABLE` |
| `mergeStateStatus` | `CLEAN` (or `UNSTABLE` — only non-required checks pending like CodeRabbit) |
| `reviewDecision` | `APPROVED` (multiple approvals from different reviewers) |
| `statusCheckRollup.state` | `SUCCESS` |
| `isDraft` | `false` |
| `requested_reviewers` | `[]` (no pending reviewer requests) |
| No branch protection | (none exists on any branch in the stack) |
| No repository rulesets | (none exist) |

GraphQL query used:
```graphql
{
repository(owner: "O", name: "R") {
pullRequest(number: N) {
mergeable
mergeStateStatus
reviewDecision
isDraft
statusCheckRollup { state }
}
}
}
```

### Context about the "not ready" PRs (#8 and #10)

- Both are **history-import PRs** — they contain 500+ commits each (preserved full history of the imported repositories), adding ~48k lines across 180+ files.
- The remaining PRs are smaller (single-digit to low-double-digit commits).
- All PRs (including #8 and #10) were created via the same `gh stack submit` flow, all with the same review/check configuration.
- The status checks on #8 and #10 all show **green/success**. Only CodeRabbit (not required) shows as not completed.

## Attempted workaround: close + reopen the "not ready" PRs

We closed and reopened PR #8 (the first "not ready" PR in the stack) to force a full server-side recompute:

```
gh pr close 8 && gh pr reopen 8
```

**Result:**
- The individual PR returned to `mergeable=MERGEABLE, reviewDecision=APPROVED` correctly.
- The stack view took ~30 seconds to reload, but **the state did not change**: PR #8 remained "not ready", PR #9 remained "blocked downstack", and the global message stayed "unable to merge as a stack".

Close+reopen did **not** invalidate the stack view's cached state. The stack view appears to maintain its own independent cache that is not invalidated by PR state changes.

## Expected behavior

Given that:
1. All PRs are mergeable (no conflicts, `MERGEABLE`).
2. All PRs are approved (`APPROVED`).
3. All required status checks pass (`SUCCESS`).
4. No branch protection, rulesets, CODEOWNERS, or merge queue block merging.
5. Close+reopen did not help.

GitHub's native stack view should reflect the actual PR state and show all 13 PRs as **"Ready"**, with the **"Merge stack (13)"** option enabled and functional. A stale cached state rendering the stack unmergeable is a blocking UX bug.

## Related

- **#323** — "Can't merge a stacked PR with no clear reason (all PRs show mergeable)". Same class of bug: stack UI state differs from API state. In our case the stack never shows as mergeable at all (no attempt to merge fails — the UI never allows the attempt). We confirm the `MERGEABLE`/`CLEAN`/`APPROVED` symptom. Our close+reopen attempt did not resolve it, suggesting a different cache invalidation path.

Contributor guide

Open the contributing guide

Research direction

No repository files or tests are named. Start by reproducing the 13-level stack in GitHub's native stack view and compare its displayed readiness with the REST and GraphQL fields listed in the report; done means the UI reflects the approved, mergeable PRs and enables "Merge stack (13)".

Written by the indexing model from the issue text.

Assessment

Tech stack
github
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.