[GH-ISSUE #399] Question: Panic when printing to two textviews #293

Closed
opened 2026-03-04 01:03:41 +03:00 by kerem · 2 comments
Owner

Originally created by @ethantrithon on GitHub (Feb 8, 2020).
Original GitHub issue: https://github.com/rivo/tview/issues/399

I'm currently working on a go game using tview, and to make testing of certain things faster, I've set up a goroutine in my main file which automatically places stones and does a few other test things. I used to have a delay of about 100ms between each stone placed, and everything was fine. I removed the delay and then I get a panic (but not all the time, just about 70-80%) which looks like:

panic: runtime error: index out of range [0] with length 0 [recovered]
	panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
github.com/rivo/tview.(*Application).Run.func1(0xc000122100)
	/home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/application.go:149 +0x82
panic(0x59c200, 0xc000017ca0)
	/usr/lib/go/src/runtime/panic.go:679 +0x1b2
github.com/rivo/tview.(*TextView).Draw(0xc00009eea0, 0x5e14e0, 0xc00015a000)
	/home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/textview.go:847 +0xa74
github.com/rivo/tview.(*Grid).Draw(0xc000158000, 0x5e14e0, 0xc00015a000)
	/home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/grid.go:613 +0x12a9
github.com/rivo/tview.(*Application).draw(0xc000122100, 0x0)
	/home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/application.go:363 +0xff
github.com/rivo/tview.(*Application).Draw.func1()
	/home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/application.go:316 +0x2a
github.com/rivo/tview.(*Application).Run(0xc000122100, 0x0, 0x0)
	/home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/application.go:253 +0x615
main.main()
	/home/ethan/code/go/igo/main.go:54 +0x930
exit status 2

where sometimes the index it's trying to access is not 0, although it mostly is, I've seen other values like 3, 7 or 15 as well.

the relevant code is:

	redrawGame := func() { application.Draw() }

	goban.View().SetChangedFunc(redrawGame)
	input.SetChangedFunc(redrawGame)
	history.SetChangedFunc(redrawGame)

	go func() {
		history.Clear()
		input.Clear()
		for _, x := range []string{
			"K10", "K11", "A1", "K9", "B1", "J10", "C1", "L10", "D1", "E1", "D9",
			"D2", "C9", "C2", "B9", "B2", "A9", "A2", "K12", "E2", "L12", "B1", "J12",
			"L11", "M11", "L9", "M10", "J9", "M9", "J11", "L8", "A5", "K8", "B5",
			"J8", "C5", "H9", "D5", "H10", "E5", "H11", "F5", "K10", "D1",
		} {
			fmt.Fprintf(history, "%s %t\n", x, goban.PlaceStoneString(x))
			fmt.Fprintf(input, x)
		}

		// goban.HLColumn(5).HLRow(5)
	}()

input and history are both TextViews, goban is a wrapper for a text view (it's essentially the main component of the go game).

Why does this crash? I'm surprised it does since in the wiki it says that

It is always safe to call Application.Draw() from the handler, and most of the time, this is the only action needed in the handler anyway.

Which yes, in this case IS the only thing I'm doing.
The commented out "highlight row/column" methods surround a line with [color]...[white] text, and then call SetText again with the updated string, but since it also panics without the call to the highlight functions, i figured that's not the root cause of the issue. Removing one of the Fprintf calls but leaving in the highlight functions has never crashed so far

Am I simply missing a check for concurrency somewhere or is this indeed a bug?
(I'm happy to provide more source code if necessary)

Originally created by @ethantrithon on GitHub (Feb 8, 2020). Original GitHub issue: https://github.com/rivo/tview/issues/399 I'm currently working on a go game using tview, and to make testing of certain things faster, I've set up a goroutine in my main file which automatically places stones and does a few other test things. I used to have a delay of about 100ms between each stone placed, and everything was fine. I removed the delay and then I get a panic (but not all the time, just about 70-80%) which looks like: ``` panic: runtime error: index out of range [0] with length 0 [recovered] panic: runtime error: index out of range [0] with length 0 goroutine 1 [running]: github.com/rivo/tview.(*Application).Run.func1(0xc000122100) /home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/application.go:149 +0x82 panic(0x59c200, 0xc000017ca0) /usr/lib/go/src/runtime/panic.go:679 +0x1b2 github.com/rivo/tview.(*TextView).Draw(0xc00009eea0, 0x5e14e0, 0xc00015a000) /home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/textview.go:847 +0xa74 github.com/rivo/tview.(*Grid).Draw(0xc000158000, 0x5e14e0, 0xc00015a000) /home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/grid.go:613 +0x12a9 github.com/rivo/tview.(*Application).draw(0xc000122100, 0x0) /home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/application.go:363 +0xff github.com/rivo/tview.(*Application).Draw.func1() /home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/application.go:316 +0x2a github.com/rivo/tview.(*Application).Run(0xc000122100, 0x0, 0x0) /home/ethan/code/go/pkg/mod/github.com/rivo/tview@v0.0.0-20200108161608-1316ea7a4b35/application.go:253 +0x615 main.main() /home/ethan/code/go/igo/main.go:54 +0x930 exit status 2 ``` where sometimes the index it's trying to access is not 0, although it mostly is, I've seen other values like 3, 7 or 15 as well. the relevant code is: ```go redrawGame := func() { application.Draw() } goban.View().SetChangedFunc(redrawGame) input.SetChangedFunc(redrawGame) history.SetChangedFunc(redrawGame) go func() { history.Clear() input.Clear() for _, x := range []string{ "K10", "K11", "A1", "K9", "B1", "J10", "C1", "L10", "D1", "E1", "D9", "D2", "C9", "C2", "B9", "B2", "A9", "A2", "K12", "E2", "L12", "B1", "J12", "L11", "M11", "L9", "M10", "J9", "M9", "J11", "L8", "A5", "K8", "B5", "J8", "C5", "H9", "D5", "H10", "E5", "H11", "F5", "K10", "D1", } { fmt.Fprintf(history, "%s %t\n", x, goban.PlaceStoneString(x)) fmt.Fprintf(input, x) } // goban.HLColumn(5).HLRow(5) }() ``` input and history are both TextViews, goban is a wrapper for a text view (it's essentially the main component of the go game). Why does this crash? I'm surprised it does since in the wiki it says that > It is always safe to call Application.Draw() from the handler, and most of the time, this is the only action needed in the handler anyway. Which yes, in this case *IS* the only thing I'm doing. The commented out "highlight row/column" methods surround a line with [color]...[white] text, and then call SetText again with the updated string, but since it also panics without the call to the highlight functions, i figured that's not the root cause of the issue. Removing one of the Fprintf calls but leaving in the highlight functions has never crashed so far Am I simply missing a check for concurrency somewhere or is this indeed a bug? (I'm happy to provide more source code if necessary)
kerem closed this issue 2026-03-04 01:03:42 +03:00
Author
Owner

@tslocum commented on GitHub (Feb 13, 2020):

It looks like this error is from Application.Draw being called on the main thread while TextView.Clear is called on another thread. Only writing to TextViews is officially supported from any goroutine. Otherwise, you must queue your code to execute on the application's main thread.

See https://rocketnine.space/post/tview-and-you/#thread-safety

<!-- gh-comment-id:586030271 --> @tslocum commented on GitHub (Feb 13, 2020): It looks like this error is from Application.Draw being called on the main thread while TextView.Clear is called on another thread. Only writing to TextViews is officially supported from any goroutine. Otherwise, you must queue your code to execute on the application's main thread. See https://rocketnine.space/post/tview-and-you/#thread-safety
Author
Owner

@rivo commented on GitHub (Feb 19, 2020):

@tslocum may be right. Here's code that should fix it:

go func() {
	app.QueueUpdate(func() {
		history.Clear()
		input.Clear()
	})
	for _, x := range []string{
		"K10", "K11", "A1", "K9", "B1", "J10", "C1", "L10", "D1", "E1", "D9",
		"D2", "C9", "C2", "B9", "B2", "A9", "A2", "K12", "E2", "L12", "B1", "J12",
		"L11", "M11", "L9", "M10", "J9", "M9", "J11", "L8", "A5", "K8", "B5",
		"J8", "C5", "H9", "D5", "H10", "E5", "H11", "F5", "K10", "D1",
	} {
		fmt.Fprintf(history, "%s %t\n", x, goban.PlaceStoneString(x))
		fmt.Fprintf(input, x)
	}

	// goban.HLColumn(5).HLRow(5)
}()

But I'm not 100% sure because I can't run your program.

You should also update to the latest commit. I had to introduce a small change to Application.QueueUpdate() to make it return after the provided function has executed. Otherwise, there could have been situations in your code where text is written to the TextView before it is cleared.

Please let me know if the panic still occurs.

<!-- gh-comment-id:588300330 --> @rivo commented on GitHub (Feb 19, 2020): @tslocum may be right. Here's code that should fix it: ```go go func() { app.QueueUpdate(func() { history.Clear() input.Clear() }) for _, x := range []string{ "K10", "K11", "A1", "K9", "B1", "J10", "C1", "L10", "D1", "E1", "D9", "D2", "C9", "C2", "B9", "B2", "A9", "A2", "K12", "E2", "L12", "B1", "J12", "L11", "M11", "L9", "M10", "J9", "M9", "J11", "L8", "A5", "K8", "B5", "J8", "C5", "H9", "D5", "H10", "E5", "H11", "F5", "K10", "D1", } { fmt.Fprintf(history, "%s %t\n", x, goban.PlaceStoneString(x)) fmt.Fprintf(input, x) } // goban.HLColumn(5).HLRow(5) }() ``` But I'm not 100% sure because I can't run your program. You should also update to the latest commit. I had to introduce a small change to [`Application.QueueUpdate()`](https://pkg.go.dev/github.com/rivo/tview?tab=doc#Application.QueueUpdate) to make it return after the provided function has executed. Otherwise, there could have been situations in your code where text is written to the `TextView` before it is cleared. Please let me know if the panic still occurs.
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#293
No description provided.