#729·lipgloss

Style.Width()/Height() panic ("makeslice: len out of range") on extreme values instead of clamping

Author: xhon-pelushiCreated Aug 16, 2026Updated Aug 16, 2026

Style.Width() and Style.Height() accept an unbounded int that flows straight into strings.Repeat with no upper bound, so a large-enough value crashes the whole program with an unrecoverable runtime panic instead of degrading gracefully (e.g. clamping or truncating).

Repro

go
package main

import (
	"math"
	"github.com/charmbracelet/lipgloss"
)

func main() {
	lipgloss.NewStyle().Width(math.MaxInt).Render("hi")
}
panic: runtime error: makeslice: len out of range

goroutine 1 [running]:
internal/bytealg.MakeNoZero(...)
strings.(*Builder).grow(...)
strings.(*Builder).Grow(...)
strings.Repeat({0x596460?, 0x1}, 0x2?)
github.com/charmbracelet/lipgloss.alignTextHorizontal(...)
	align.go:44
github.com/charmbracelet/lipgloss.Style.Render(...)
	style.go:496

Same crash for .Height(math.MaxInt), via alignTextVertical's strings.Repeat("\n", height-strHeight) a few lines below.

Root cause

align.go:

go
func alignTextHorizontal(str string, pos Position, width int, style *ansi.Style) string {
	...
	shortAmount := widestLine - lineWidth
	shortAmount += max(0, width-(shortAmount+lineWidth))
	if shortAmount > 0 {
		...
		s := strings.Repeat(" ", shortAmount)  // align.go:44 (Left/Right), similar for Center

and alignTextVertical:

go
case Top:
	return str + strings.Repeat("\n", height-strHeight)

Neither function bounds width/height before it's used as a strings.Repeat count. With a pathological value, shortAmount (or height-strHeight) becomes large enough that the Go runtime refuses the allocation outright — this isn't a slow-but-technically-possible allocation, it's a hard makeslice: len out of range rejection, so there's no configuration or amount of RAM that makes this succeed.

Why I think this is worth guarding against, not just a fuzz-only value

I hit this by intentionally probing extreme values, but the shape of bug that produces one isn't exotic: this library is a low-level building block for terminal-width-driven layout, so a caller computing a width from term.GetSize() plus/minus some arithmetic (subtracting borders, margins, a miscomputed "remaining space" in a flex-style layout, etc.) is exactly the kind of code that can accidentally produce an extreme or wrapped-around value one step removed from the actual mistake — and right now that turns into a hard, unrecoverable process crash here rather than a visibly wrong-but-survivable render. (For context: I ran into the same general failure shape — an unbounded width/count flowing into an unchecked allocation or subtraction — independently in eza, bat, and muesli/reflow this week, so it seems to be a fairly common blind spot in terminal-formatting code generally, not specific to this codebase.)

Suggested fix

Clamp shortAmount / height-strHeight to something sane (or just skip the repeat when the value exceeds a reasonable bound, e.g. some multiple of math.MaxInt32 or an internal max-terminal-width constant) before calling strings.Repeat. Happy to send a PR if a specific clamp value/approach is preferred — didn't want to guess at the right ceiling without checking first.

Versions

  • github.com/charmbracelet/lipgloss at current main (module resolved to require Go >= 1.25 at time of testing)
  • Go 1.25.0, linux/amd64