Skip to content

runtime error: slice bounds out of range [:-573] #74

Description

@patsevanton

Environment

  • reposcan: v1.4.0

Description

reposcan TUI crashes with a recovered panic when opening repo details (uncommitted files view).

Caught panic:
runtime error: slice bounds out of range [:-573]

Stack trace

github.com/mabd-dev/reposcan/internal/render/tui/repodetails.(*Model).buildUncommittedFiles
	internal/render/tui/repodetails/view.go:47
github.com/mabd-dev/reposcan/internal/render/tui/repodetails.(*Model).View
	internal/render/tui/repodetails/view.go:25
github.com/mabd-dev/reposcan/internal/render/tui.Model.View
	internal/render/tui/view.go:29
github.com/charmbracelet/bubbletea.(*Program).eventLoop
github.com/mabd-dev/reposcan/internal/render/tui.Render
	internal/render/tui/main.go:87

Full panic:

Caught panic:

runtime error: slice bounds out of range [:-573]

Restoring terminal...

goroutine 1 [running]:
runtime/debug.Stack()
	/opt/hostedtoolcache/go/1.24.13/x64/src/runtime/debug/stack.go:26 +0x5e
runtime/debug.PrintStack()
	/opt/hostedtoolcache/go/1.24.13/x64/src/runtime/debug/stack.go:18 +0x13
github.com/charmbracelet/bubbletea.(*Program).recoverFromPanic(0xc00030c500, {0x96fdc0, 0xc000578d68})
	/home/runner/go/pkg/mod/github.com/charmbracelet/bubbletea@v1.3.6/tea.go:810 +0xac
github.com/charmbracelet/bubbletea.(*Program).Run.func2()
	/home/runner/go/pkg/mod/github.com/charmbracelet/bubbletea@v1.3.6/tea.go:601 +0xe8
panic({0x96fdc0?, 0xc000578d68?})
	/opt/hostedtoolcache/go/1.24.13/x64/src/runtime/panic.go:792 +0x132
github.com/mabd-dev/reposcan/internal/render/tui/repodetails.(*Model).buildUncommittedFiles(0xc0010589b0)
	/home/runner/work/reposcan/reposcan/internal/render/tui/repodetails/view.go:47 +0x6a7
github.com/mabd-dev/reposcan/internal/render/tui/repodetails.(*Model).View(0xc0010589b0)
	/home/runner/work/reposcan/reposcan/internal/render/tui/repodetails/view.go:25 +0x457
github.com/mabd-dev/reposcan/internal/render/tui.Model.View({0x0, 0xba, 0x2e, {{{0xc0001fe9c0, 0x7}, {0xc0001fea88, 0x7}, {0xc0001feba8, 0x7}, {0xc0001fea30, ...}, ...}, ...}, ...})
	/home/runner/work/reposcan/reposcan/internal/render/tui/view.go:29 +0x1d8
github.com/charmbracelet/bubbletea.(*Program).eventLoop(0xc00030c500, {0xab8648?, 0xc0007c2000?}, 0xc00074bc00)
	/home/runner/go/pkg/mod/github.com/charmbracelet/bubbletea@v1.3.6/tea.go:533 +0x892
github.com/charmbracelet/bubbletea.(*Program).Run(0xc00030c500)
	/home/runner/go/pkg/mod/github.com/charmbracelet/bubbletea@v1.3.6/tea.go:679 +0xb56
github.com/mabd-dev/reposcan/internal/render/tui.Render({0x1, {0xc000afc000, 0x47, 0xc32}, 0xc32, {0xc29ffca540079a6c, 0x11228189c, 0xe9cda0}, {0xc000d81008, 0x73, ...}}, ...)
	/home/runner/work/reposcan/reposcan/internal/render/tui/main.go:87 +0x785
github.com/mabd-dev/reposcan/cmd/reposcan.run({{0xc000022b40, 0x1, 0x1}, {0xc0001ca488, 0x29, 0x47}, {0x9a368b, 0x5}, {{0x9a6abf, 0xb}, ...}, ...})
	/home/runner/work/reposcan/reposcan/cmd/reposcan/rootCmd.go:166 +0x1d8
github.com/mabd-dev/reposcan/cmd/reposcan.init.func2(0xdf77a0, {0x9a3263?, 0x4?, 0x9a31a7?})
	/home/runner/work/reposcan/reposcan/cmd/reposcan/rootCmd.go:60 +0x398
github.com/spf13/cobra.(*Command).execute(0xdf77a0, {0xc0000220a0, 0x0, 0x0})
	/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:983 +0xad4
github.com/spf13/cobra.(*Command).ExecuteC(0xdf77a0)
	/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:1115 +0x44f
github.com/spf13/cobra.(*Command).Execute(...)
	/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:1039
github.com/mabd-dev/reposcan/cmd/reposcan.Execute()
	/home/runner/work/reposcan/reposcan/cmd/reposcan/main.go:13 +0x1a
main.main()
	/home/runner/work/reposcan/reposcan/main.go:8 +0xf
tui error: program was killed: program experienced a panic

Likely cause

In buildUncommittedFiles:

maxUncommitedFilesToShow := m.height - 3
trimUncommitedFiles := len(files) > m.height-3
if trimUncommitedFiles {
    files = files[:maxUncommitedFilesToShow]
}

[:-573] means m.height is negative (~-570). Slice high bound is not clamped to >= 0.

Can happen if:

  • WindowSizeMsg arrives with height 0 / negative (resize, tmux, restore)
  • m.height is uninitialized before the first size message
  • height is computed as termHeight - header and underflows

Current if maxUncommitedFilesToShow <= 0 { return lines } on main may not be in the crashing build (panic line is view.go:47).

Suggested fix

Clamp before slicing, and do not slice with a negative high:

maxUncommitedFilesToShow := m.height - 3
if maxUncommitedFilesToShow < 0 {
    maxUncommitedFilesToShow = 0
}
if maxUncommitedFilesToShow == 0 {
    return nil
}
if maxUncommitedFilesToShow > len(files) {
    maxUncommitedFilesToShow = len(files)
}
files = files[:maxUncommitedFilesToShow]

Also clamp m.height/m.width on tea.WindowSizeMsg (max(0, msg.Height)).

Guard f[:2] when a change line is shorter than 2 chars.

Expected

TUI does not panic on small/invalid terminal size; empty or truncated file list is fine.

Actual

Process panics, Bubble Tea recovers, TUI exits: program was killed: program experienced a panic.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions