Skip to content

fix(tui): capture panics and harden GitHub workflow dispatch#362

Merged
jongio merged 2 commits into
mainfrom
go/issue-361
Jul 22, 2026
Merged

fix(tui): capture panics and harden GitHub workflow dispatch#362
jongio merged 2 commits into
mainfrom
go/issue-361

Conversation

@jongio

@jongio jongio commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Fixes #361

What

  • Add crashlog.GuardTUI, deferred on the root model's Update, View, and Init. It recovers an in-flight panic, writes a crash report (with the real stack) to DataDir()/crashes, records the path, then re-panics so Bubble Tea still restores the terminal. cmd/root.go prints the report path after the program exits.
  • Guard a nil GitHub client in handleWorkflowDispatchInputs so it shows a failure toast instead of a nil dereference.
  • Show the workflow-dispatch inputs in a multi-line composer (ShowMultilineInputWithValue) instead of a single-line input.
  • Drop handleWindowSizeMsg's always-nil tea.Cmd return (surfaced by unparam once the Update guard defer broke return pass-through).

Why

Dispatching a GitHub Actions workflow from the GitHub panel crashed the whole TUI with a generic "program was killed: program experienced a panic" and wrote no crash report: Bubble Tea catches panics in the model's Update/View, swallows the value, and returns only a generic error, so main's top-level recover never runs. That made the crash undiagnosable. The inputs step also fed multi-line key=value content into a single-line input that couldn't hold or accept newlines, and the dispatch call lacked the nil-client guard its sibling already has.

How

The panic is in the main event-loop goroutine (that's why the error is the wrapped ErrProgramKilled), so GuardTUI on Update/View/Init catches it. debug.Stack() inside the deferred recover still points at the original panic site, so the report is diagnosable; re-panicking hands control back to Bubble Tea's own recover, which restores the terminal. Now any TUI panic is captured, and the dispatch path no longer crashes.

Testing

  • go build ./... passes
  • go test ./... passes (full suite and -race)
  • go vet ./... passes
  • New tests added for new functionality
  • Existing tests still pass

New regression tests cover the full dispatch flow (no panic plus success toast), the panic-capture guard on Update/View/Init (crash report written and re-panic), the nil-client path, and the multi-line modal. Also clean: golangci-lint, gofumpt, deadcode, govulncheck.

Screenshots

N/A (terminal UI). The inputs modal now renders as a multi-line composer: Enter inserts a newline, Ctrl+D submits, Esc cancels.

Dispatching a GitHub Actions workflow crashed the whole TUI with a
generic "program was killed: program experienced a panic" and left no
crash report, because Bubble Tea catches panics in the model's
Update/View, swallows the value, and returns only a generic error, so
main's top-level recover never runs.

- Add crashlog.GuardTUI, deferred on the root model's Update, View, and
  Init: it recovers the in-flight panic, writes a crash report with the
  preserved stack to DataDir()/crashes, records the path, then re-panics
  so Bubble Tea still restores the terminal. cmd/root.go surfaces the
  report path after the program exits (a message printed mid-panic would
  be lost with the alternate screen).
- Guard a nil GitHub client in handleWorkflowDispatchInputs so it yields
  a failure toast instead of a nil dereference.
- Show the workflow-dispatch inputs in a multi-line composer
  (ShowMultilineInputWithValue) to match its key=value-per-line content;
  the single-line input could neither hold nor let the user add newlines.
- Drop handleWindowSizeMsg's always-nil tea.Cmd return, surfaced by
  golangci-lint unparam once the Update guard defer broke return
  pass-through.

Adds regression tests for the full dispatch flow (no panic + success
toast), the panic-capture guard on Update/View/Init, the nil-client
path, and the multi-line modal.

Fixes #361

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2fe7a260-26ac-4066-8f4f-369ab6a38550
@jongio jongio added the bug Something isn't working label Jul 22, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2fe7a260-26ac-4066-8f4f-369ab6a38550
@jongio
jongio merged commit 9fbbaa8 into main Jul 22, 2026
4 checks passed
@jongio
jongio deleted the go/issue-361 branch July 22, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix TUI panic when dispatching a GitHub Actions workflow

1 participant