Skip to content

fix(tty): fall back to default dimensions when terminal size is 0x0 - #1836

Merged
andrinoff merged 2 commits into
charmbracelet:mainfrom
AdamMagued:fix-fallback-terminal-size
Oct 2, 2026
Merged

andrinoff merged 2 commits into
charmbracelet:mainfrom
AdamMagued:fix-fallback-terminal-size

Conversation

@AdamMagued

Copy link
Copy Markdown
Contributor

Problem

When running Bubble Tea v2 applications on serial consoles, headless setups, or terminals where window dimensions are not yet configured or reported as 0x0 (e.g. stty rows 0 cols 0), term.GetSize returns (0, 0, nil). Bubble Tea sets p.width = 0 and p.height = 0 and passes these dimensions to the renderer and model. Because the viewport height and width are 0, rendered output lines are clipped, resulting in a completely blank screen.

Root Cause

In Program.Run and Program.checkResize:

  • term.GetSize(p.ttyOutput.Fd()) can return (0, 0, nil) or non-positive values without returning an error.
  • Previously, these dimensions were assigned directly to p.width and p.height without verifying they are positive.
  • When s.height is 0 in cursedRenderer, line buffering clips lines, producing no visible content.

Solution

  1. Added fallbackDimensions(width, height int) (int, int) helper on *Program with standard terminal defaults (defaultWidth = 80, defaultHeight = 24).
  2. If width <= 0, fall back to COLUMNS (checking program environment first, then os.Getenv) if positive, otherwise fall back to 80.
  3. If height <= 0, fall back to LINES (checking program environment first, then os.Getenv) if positive, otherwise fall back to 24.
  4. Applied fallback in both Program.Run and Program.checkResize.
  5. Added unit tests in tty_test.go covering fallback to 80x24, fallback to COLUMNS/LINES, handling invalid or zero env values, and initial window size message dispatch.

Fixes #1828

@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.21%. Comparing base (ff51ba4) to head (383d7da).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
tty.go 78.26% 3 Missing and 2 partials ⚠️
tea.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1836      +/-   ##
==========================================
+ Coverage   59.91%   60.21%   +0.30%     
==========================================
  Files          25       25              
  Lines        1342     1365      +23     
==========================================
+ Hits          804      822      +18     
- Misses        449      452       +3     
- Partials       89       91       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@andrinoff andrinoff left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, fix those and it is good to go!

Comment thread tea.go Outdated
width, height = w, h
}

width, height = p.fallbackDimensions(width, height)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fallback also runs when the output isn't a terminal at all, such as output to a buffer, a pipe, or a Wish/SSH session. Apps that used to receive a 0x0 size there will now get a made-up 80x24. Moving this line inside the if p.ttyOutput != nil block above would limit the fix to the actual bug

Comment thread tty.go
cols = p.environ.Getenv("COLUMNS")
}
if cols == "" {
cols = os.Getenv("COLUMNS")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the app passed its own environment with WithEnvironment, which is the usual Wish setup, this falls back to the server's own COLUMNS/LINES. Those belong to the wrong machine, so it should only read the program's environment and skip os.Getenv

Comment thread tty.go
lines = p.environ.Getenv("LINES")
}
if lines == "" {
lines = os.Getenv("LINES")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the app passed its own environment with WithEnvironment, which is the usual Wish setup, this falls back to the server's own COLUMNS/LINES. Those belong to the wrong machine, so it should only read the program's environment and skip os.Getenv

@AdamMagued

Copy link
Copy Markdown
Contributor Author

Updated per your review:

  1. Restricted fallbackDimensions execution to the if p.ttyOutput != nil block in Run(), preserving 0x0 dimensions for non-terminal outputs (buffers, pipes).
  2. Adjusted fallbackDimensions in tty.go so that when p.environ is supplied via WithEnvironment, it only queries the program's environment without falling back to host os.Getenv.
    All unit tests pass.

@andrinoff andrinoff left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@andrinoff
andrinoff merged commit 96d69d2 into charmbracelet:main Oct 2, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v2: blank screen when tty size is 0x0 (e.g. in a serial console)

2 participants