Fix potential panics throughout the codebase with graceful error handling
This PR addresses multiple potential panic sources throughout the codebase, replacing them with robust error handling to improve application stability and user experience.
Issues Fixed
1. Explicit Panic Calls
The application had several locations where panic() was called when configuration loading failed:
-
main.go- Application startup would panic on config errors -
internal/terminal/handler/handler.go- Terminal setup would panic -
internal/terminal/handler/ghworkflowhistory.go- Workflow history setup would panic -
internal/terminal/handler/keymap.go- Global keymap initialization would panic
Solution: Replaced all panics with graceful error handling. Config loading now falls back to sensible defaults when files are missing, and the application exits cleanly with helpful error messages instead of crashing.
2. Array/Slice Access Without Bounds Checking
Multiple locations accessed array indices without validating length:
// Before - could panic if selectedRow has < 5 elements
var selectedRow = m.tableTrigger.SelectedRow()
if selectedRow[1] == "input" {
m.textInput.SetValue(selectedRow[4])
}
// After - safe with bounds checking
var selectedRow = m.tableTrigger.SelectedRow()
if len(selectedRow) > 4 && selectedRow[1] == "input" {
m.textInput.SetValue(selectedRow[4])
}
Files affected:
-
internal/terminal/handler/ghtrigger.go- Fixed multipleSelectedRow()accesses -
internal/terminal/handler/taboptions.go- Added bounds checking for options arrays
3. Nil Pointer Dereferences
Test code had potential nil pointer access:
// Before - workflow.Workflow could be nil after error
workflow, err := githubUseCase.InspectWorkflow(ctx, input)
if err != nil {
t.Error(err)
}
for i, w := range workflow.Workflow.Inputs { // Panic if workflow.Workflow is nil
// After - proper nil checking
workflow, err := githubUseCase.InspectWorkflow(ctx, input)
if err != nil {
t.Error(err)
return
}
if workflow == nil || workflow.Workflow == nil {
t.Error("workflow or workflow.Workflow is nil")
return
}
for i, w := range workflow.Workflow.Inputs {
4. Unsafe Map Access
Fixed potential panics from accessing maps with keys that might not exist:
// Before - could panic if key doesn't exist
go o.optionsWithFunc[o.cursor]()
// After - safe map access with existence check
if fn, exists := o.optionsWithFunc[o.cursor]; exists {
go fn()
}
Testing
- ✅ All builds complete successfully
- ✅ Test suite runs without panics (previously had
runtime error: invalid memory address or nil pointer dereference) - ✅ Application starts and handles missing configurations gracefully
- ✅ Edge cases like empty tables and invalid selections are handled safely
The application now provides a much better user experience by handling errors gracefully instead of crashing unexpectedly, while maintaining full backward compatibility.
[!WARNING]
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/repos/canack/tc/actions/runs
- Triggering command:
/tmp/go-build3227885281/b277/repository.test -test.testlogfile=/tmp/go-build3227885281/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build2894260525/b277/repository.test -test.testlogfile=/tmp/go-build2894260525/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true(http block)https://api.github.com/repos/canack/tc/actions/workflows
- Triggering command:
/tmp/go-build3227885281/b277/repository.test -test.testlogfile=/tmp/go-build3227885281/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build2894260525/b277/repository.test -test.testlogfile=/tmp/go-build2894260525/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true(http block)https://api.github.com/repos/canack/tc/contents/.github/workflows/dispatch_test.yaml
- Triggering command:
/tmp/go-build3227885281/b289/usecase.test -test.testlogfile=/tmp/go-build3227885281/b289/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build3087692475/b001/usecase.test -test.testlogfile=/tmp/go-build3087692475/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true(http block)- Triggering command:
/tmp/go-build2894260525/b289/usecase.test -test.testlogfile=/tmp/go-build2894260525/b289/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true(http block)https://api.github.com/repos/fleimkeipa/dvpwa
- Triggering command:
/tmp/go-build3227885281/b277/repository.test -test.testlogfile=/tmp/go-build3227885281/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build2894260525/b277/repository.test -test.testlogfile=/tmp/go-build2894260525/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true(http block)https://api.github.com/repos/fleimkeipa/dvpwa/actions/workflows
- Triggering command:
/tmp/go-build3227885281/b277/repository.test -test.testlogfile=/tmp/go-build3227885281/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build2894260525/b277/repository.test -test.testlogfile=/tmp/go-build2894260525/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true(http block)https://api.github.com/repos/fleimkeipa/dvpwa/branches
- Triggering command:
/tmp/go-build3227885281/b277/repository.test -test.testlogfile=/tmp/go-build3227885281/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build2894260525/b277/repository.test -test.testlogfile=/tmp/go-build2894260525/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true(http block)https://api.github.com/repos/fleimkeipa/dvpwa/contents/.github/workflows/build.yml
- Triggering command:
/tmp/go-build3227885281/b277/repository.test -test.testlogfile=/tmp/go-build3227885281/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build2894260525/b277/repository.test -test.testlogfile=/tmp/go-build2894260525/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true(http block)https://api.github.com/repos/termkit/gama/releases/latest
- Triggering command:
/tmp/go-build3227885281/b300/version.test -test.testlogfile=/tmp/go-build3227885281/b300/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build2894260525/b300/version.test -test.testlogfile=/tmp/go-build2894260525/b300/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true(http block)https://api.github.com/user
- Triggering command:
/tmp/go-build3227885281/b277/repository.test -test.testlogfile=/tmp/go-build3227885281/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build2894260525/b277/repository.test -test.testlogfile=/tmp/go-build2894260525/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true(http block)https://api.github.com/user/repos
- Triggering command:
/tmp/go-build3227885281/b289/usecase.test -test.testlogfile=/tmp/go-build3227885281/b289/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build3227885281/b277/repository.test -test.testlogfile=/tmp/go-build3227885281/b277/testlog.txt -test.paniconexit0 -test.timeout=10m0s(http block)- Triggering command:
/tmp/go-build3087692475/b001/usecase.test -test.testlogfile=/tmp/go-build3087692475/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true(http block)If you need me to access, download, or install something from one of these locations, you can either:
- Configure Actions setup steps to set up my environment, which run before the firewall is enabled
- Add the appropriate URLs or hosts to the custom allowlist in this repository's Copilot coding agent settings (admins only)
Original prompt
find the potential panics and fix it
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.