Skip to content

viewport: panic with slice bounds out of range when height is negative or zero #879

@semihbkgr

Description

@semihbkgr

Description

The viewport panics with slice bounds out of range when the Height is set to a negative or zero value. This commonly occurs when resizing the terminal window to be very small while using a viewport alongside other components (e.g., textarea).

Stack Trace

runtime error: slice bounds out of range [8:4]

goroutine 1 [running]:
github.com/charmbracelet/bubbles/viewport.Model.visibleLines(...)
        viewport/viewport.go:150
github.com/charmbracelet/bubbles/viewport.(*Model).GotoBottom(...)
        viewport/viewport.go:348

Root Cause

In visibleLines() (viewport.go:143-150), when Height becomes negative:

func (m Model) visibleLines() (lines []string) {
    h := m.Height - m.Style.GetVerticalFrameSize()  // h can be negative
    // ...
    if len(m.lines) > 0 {
        top := max(0, m.YOffset)
        bottom := clamp(m.YOffset+h, top, len(m.lines))  // bottom can be < top
        lines = m.lines[top:bottom]  // PANIC: invalid slice bounds
    }
}

When h is negative and YOffset is positive (from a previous scroll), bottom becomes less than top, causing the panic.

Steps to Reproduce

  1. Create a viewport with another component that takes up vertical space
  2. Calculate viewport height as: msg.Height - otherComponent.Height() - gap
  3. Shrink the terminal window until the calculated height becomes negative
  4. The viewport panics

Minimal Example

case tea.WindowSizeMsg:
    m.viewport.Height = msg.Height - m.textarea.Height() - 2  // Can go negative
    m.viewport.GotoBottom()  // Triggers panic

Suggested Fix

Add a guard in visibleLines() to handle the case where top >= bottom:

if len(m.lines) > 0 {
    top := max(0, m.YOffset)
    bottom := clamp(m.YOffset+h, top, len(m.lines))
    if top >= bottom {
        return nil
    }
    lines = m.lines[top:bottom]
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions