[GH-ISSUE #166] Crashing in goroutine causes terminal to become unresponsive #132

Closed
opened 2026-03-04 01:02:13 +03:00 by kerem · 6 comments
Owner

Originally created by @JesseAldridge on GitHub (Sep 11, 2018).
Original GitHub issue: https://github.com/rivo/tview/issues/166

package main

import (
	"os"
	"os/exec"

	"github.com/gdamore/tcell"
	"github.com/rivo/tview"
)

func crash() int {
	my_list := []int{1, 2, 3}
	return my_list[5]
}

func main() {
	app := tview.NewApplication()

	app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		k := event.Key()
		if k == tcell.KeyEnter {
			go crash()
		}
		return event
	})

	box := tview.NewBox().SetBorder(true).SetTitle("Hello, world!")
	if err := app.SetRoot(box, true).Run(); err != nil {
		panic(err)
	}
}
Originally created by @JesseAldridge on GitHub (Sep 11, 2018). Original GitHub issue: https://github.com/rivo/tview/issues/166 ``` package main import ( "os" "os/exec" "github.com/gdamore/tcell" "github.com/rivo/tview" ) func crash() int { my_list := []int{1, 2, 3} return my_list[5] } func main() { app := tview.NewApplication() app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { k := event.Key() if k == tcell.KeyEnter { go crash() } return event }) box := tview.NewBox().SetBorder(true).SetTitle("Hello, world!") if err := app.SetRoot(box, true).Run(); err != nil { panic(err) } } ```
kerem closed this issue 2026-03-04 01:02:14 +03:00
Author
Owner

@rivo commented on GitHub (Sep 11, 2018):

I tried your source code and it didn't become unresponsive for me (on a Mac). Ctrl-C still stops the program as expected.

A panic in a goroutine will just crash that goroutine. If you want tview to react to a panic (usually, this means shutting down the application), you'll need to propagate the panic to the main goroutine.

This is not really an issue with tview but rather Go's general behaviour. I'll close this for now but will reopen in case we do identify anything that needs to be done in tview.

<!-- gh-comment-id:420171148 --> @rivo commented on GitHub (Sep 11, 2018): I tried your source code and it didn't become unresponsive for me (on a Mac). Ctrl-C still stops the program as expected. A panic in a goroutine will just crash that goroutine. If you want `tview` to react to a panic (usually, this means shutting down the application), you'll need to propagate the panic to the main goroutine. This is not really an issue with `tview` but rather Go's general behaviour. I'll close this for now but will reopen in case we do identify anything that needs to be done in `tview`.
Author
Owner

@JesseAldridge commented on GitHub (Sep 11, 2018):

Not sure I'm understanding. Here is a gif that will hopefully clarify:
crash_test

It looks like the issue is actually not that the terminal becomes unresponsive, but that input stops rendering. In that gif I ran the code above (with the bad imports removed), after it crashes I hit a bunch of random keys. Then I type echo "hello". The keystrokes are apparently still being processed by bash, but just not rendering properly. Hitting Ctrl-C doesn't remedy the situation.

So you're saying that after the goroutine crashes the tview gui should continue functioning? That appears not to have happened in my case.

<!-- gh-comment-id:420188041 --> @JesseAldridge commented on GitHub (Sep 11, 2018): Not sure I'm understanding. Here is a gif that will hopefully clarify: ![crash_test](https://user-images.githubusercontent.com/191903/45346961-afc14680-b55f-11e8-9a17-2f6373583183.gif) It looks like the issue is actually not that the terminal becomes unresponsive, but that input stops rendering. In that gif I ran the code above (with the bad imports removed), after it crashes I hit a bunch of random keys. Then I type `echo "hello"`. The keystrokes are apparently still being processed by bash, but just not rendering properly. Hitting Ctrl-C doesn't remedy the situation. So you're saying that after the goroutine crashes the tview gui should continue functioning? That appears not to have happened in my case.
Author
Owner

@JesseAldridge commented on GitHub (Sep 11, 2018):

I'm also on a mac. High Sierra with iterm2.

<!-- gh-comment-id:420188720 --> @JesseAldridge commented on GitHub (Sep 11, 2018): I'm also on a mac. High Sierra with iterm2.
Author
Owner

@rivo commented on GitHub (Sep 11, 2018):

I didn't say the tview GUI should continue functioning. In fact, I would say you should try to avoid panics in goroutines as the result will be undefined, as you can see. Go writes to stderr when it panics. I don't know how this affects the terminal session but obviously it doesn't in a good way.

You may be able to recover from this by running the reset command.

<!-- gh-comment-id:420208750 --> @rivo commented on GitHub (Sep 11, 2018): I didn't say the `tview` GUI should continue functioning. In fact, I would say you should try to avoid panics in goroutines as the result will be undefined, as you can see. Go writes to stderr when it panics. I don't know how this affects the terminal session but obviously it doesn't in a good way. You may be able to recover from this by running the `reset` command.
Author
Owner

@JesseAldridge commented on GitHub (Sep 12, 2018):

Yeah looks like I just need to call app.Stop() and recover from the goroutine.
This works well:

package main

import (
	"github.com/gdamore/tcell"
	"github.com/rivo/tview"
)

func crash(app *tview.Application) int {
	defer func() {
		if r := recover(); r != nil {
			app.Stop()
		}
	}()
	my_list := []int{1, 2, 3}
	return my_list[5]
}

func main() {
	app := tview.NewApplication()

	app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		k := event.Key()
		if k == tcell.KeyEnter {
			go crash(app)
		}
		return event
	})

	box := tview.NewBox().SetBorder(true).SetTitle("Hello, world!")
	if err := app.SetRoot(box, true).Run(); err != nil {
		panic(err)
	}
}
<!-- gh-comment-id:420471209 --> @JesseAldridge commented on GitHub (Sep 12, 2018): Yeah looks like I just need to call `app.Stop()` and `recover` from the goroutine. This works well: ``` package main import ( "github.com/gdamore/tcell" "github.com/rivo/tview" ) func crash(app *tview.Application) int { defer func() { if r := recover(); r != nil { app.Stop() } }() my_list := []int{1, 2, 3} return my_list[5] } func main() { app := tview.NewApplication() app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { k := event.Key() if k == tcell.KeyEnter { go crash(app) } return event }) box := tview.NewBox().SetBorder(true).SetTitle("Hello, world!") if err := app.SetRoot(box, true).Run(); err != nil { panic(err) } } ```
Author
Owner

@rivo commented on GitHub (Sep 25, 2018):

Yes, this should be a good way of dealing with it. I think you can even print the panic's callstack after app.Stop().

<!-- gh-comment-id:424373796 --> @rivo commented on GitHub (Sep 25, 2018): Yes, this should be a good way of dealing with it. I think you can even print the panic's callstack after `app.Stop()`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#132
No description provided.