`submit` loops forever after a failed stack delete: stale `pending_submit` modify state has no supported way out
- Langage dominant
- Go
- Étoiles
- 1.5k
- Forks
- 70
- Merge moyen
- 1 j 8 h
- PR mergées (30 j)
- 7
Description
## Summary
After a `gh stack submit` fails with the HTTP 422 from #428, the modify session state left in `.git/gh-stack-modify-state` keeps pointing at the old stack, so **every subsequent `gh stack submit` retries the same impossible delete**. The error tells you to "Run `gh stack submit` again to retry", but the retry can never succeed, and no CLI command clears the state. The only escape is deleting an internal file by hand.
This is separate from #428: that issue is about the 422 itself. This one is about being unable to recover from it.
Compounding it, the failed `unstack` is **partially applied** — the open PRs really are removed from the stack on GitHub — so the repository is left in a state that matches neither the local metadata nor the pre-submit state.
## Reproduction
Starting from a submitted stack (`#10`) whose bottom layers are merged — `#101`, `#102` merged; `#103 → #104 → #105` open:
1. `gh stack modify`, insert a new branch mid-stack (between `#103` and `#104`), `Ctrl+S`. The modify applies locally.
2. `gh stack submit`, answer `Yes` to "Overwrite the existing stack on GitHub?"
```
Checking stack state...
Skipping 2 merged branches
? The local stack has been modified. Overwrite the existing stack on GitHub? Yes
⚠ Failed to delete existing stack: HTTP 422: Pull requests #101, #102 cannot be removed from this stack (.../stacks/10/unstack)
Run `gh stack submit` again to retry
```
3. Run `gh stack submit` again — and again. Identical output every time.
### The state that causes it
`.git/gh-stack-modify-state`:
```json
{
"schema_version": 1,
"phase": "pending_submit",
"prior_remote_stack_id": "900001",
...
}
```
`900001` is the internal id of stack `#10`. Every `submit` reads `prior_remote_stack_id` from this file and re-attempts the delete, which GitHub will never allow while the stack contains merged PRs.
Editing `.git/gh-stack` (removing the merged branch entries) does **not** help — the modify-state file is a second, independent store, and it is the one `submit` consults.
### The partial unstack
After the first failed submit, GitHub's side had already changed:
```
$ gh api repos/OWNER/REPO/stacks
stack 10 open=false prs=[101, 102]
```
The open PRs `#103`, `#104`, `#105` were successfully removed and now belong to no stack at all; only the two merged PRs remain. So `unstack` removed what it could and reported total failure. Local metadata still described all five.
## Available exits, none of them good
- `gh stack submit` — loops forever, as above.
- `gh stack modify --abort` — would discard the completed mid-stack insertion, which is the work the user is trying to keep.
- `gh stack unstack 10` — cannot help; GitHub refuses to remove the merged PRs, which is the original 422.
- Editing `.git/gh-stack` — no effect, wrong file.
- **`rm .git/gh-stack-modify-state`** — the only thing that works.
After removing that file, `gh stack submit` succeeded immediately and did the right thing:
```
✓ Created PR #106 for
✓ Updated base branch for PR #104 to
✓ Stack created on GitHub with 4 PRs (stack #11)
```
Which shows the operation was viable all along — only the stale `prior_remote_stack_id` was blocking it.
## Expected behavior
1. When the delete fails with a 422 that **cannot** succeed on retry (merged PRs can never be removed from a stack), don't advise retrying. Fall back to creating a new stack, or say plainly that the old stack cannot be dissolved and offer that as a choice.
2. Provide a supported way to clear a stuck `pending_submit` modify state without discarding the applied modify — e.g. a counterpart to `gh stack modify --abort` such as `--forget`/`--done` that drops the session but keeps the local restructuring.
3. Reconcile the partial unstack: if some PRs were removed and others refused, report that, and update local metadata to match what actually happened on the server.
## Related
- #428 — the 422 itself (new bottom branch after a merge). Same root cause, different trigger; this report covers the unrecoverable state afterwards.
- #382 — mid-stack insertion strands merged PRs.
- #372 — `unstack` reporting generic errors instead of the real API rejection.
## Environment
- `gh` 2.97.0
- `gh-stack` v0.1.0
- git 2.50.1 (Apple Git-155)
- macOS 26.6, darwin/arm64
Guide de contribution
Ouvrir le guide de contribution
Piste de recherche
Start with the `gh stack submit` handling for `.git/gh-stack-modify-state`, then compare the `gh stack modify --abort` and `gh stack unstack` flows. Reproduce the failed delete with the documented merged and open PR layout. Done means a failed partial unstack is reported and reconciled, and users have a supported recovery path that preserves the applied modification instead of retrying the stale `pending_submit` state.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- github, go
- Domaine
- cli
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- Active
- Clarté
- Plutôt claire
- Accessibilité débutants
- 55/100