`submit` loops forever after a failed stack delete: stale `pending_submit` modify state has no supported way out
- Lenguaje dominante
- Go
- Estrellas
- 1.5k
- Forks
- 70
- Merge medio
- 1 d 8 h
- PR fusionados (30 d)
- 7
Descripción
## 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
Guía de contribución
Línea de trabajo
Comienza con el manejo de `gh stack submit` para `.git/gh-stack-modify-state` y luego compara los flujos de `gh stack modify --abort` y `gh stack unstack`. Reproduce el borrado fallido con la disposición documentada de un PR mergeado y uno abierto. Se considera terminado cuando un unstack parcial fallido se notifica y se reconcilia, y los usuarios tienen una ruta de recuperación compatible que conserva la modificación aplicada en lugar de volver a intentar el estado obsoleto `pending_submit`.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- github, go
- Área
- cli
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Activo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 55/100