Skip to content

ZeroDivisionError parsing pixel mouse events when terminal pixel size is (0, 0) #6706

Description

@mavik1

The bug

XTermParser.parse_mouse_code() raises ZeroDivisionError when pixel mouse
reporting is enabled and the terminal's character-cell dimensions are valid,
but its pixel dimensions are reported as zero.

On Linux, terminal pixel dimensions may legitimately be reported as zero when
the terminal, PTY, multiplexer, or remote session does not provide pixel
geometry. A (0, 0) pixel size means that the dimensions are unavailable; it
does not mean the terminal has a literal zero-pixel area.

The parser currently checks whether terminal_pixel_size and terminal_size
are None, but does not check whether their values are positive:

if (
    self.mouse_pixels
    and self.terminal_pixel_size is not None
    and self.terminal_size is not None
):
    pixel_width, pixel_height = self.terminal_pixel_size
    width, height = self.terminal_size
    x_ratio = pixel_width / width
    y_ratio = pixel_height / height
    x /= x_ratio
    y /= y_ratio

For terminal_pixel_size == (0, 0), x_ratio and y_ratio are zero. The next
division raises ZeroDivisionError.

In a running application this occurs in Textual's terminal input thread when
the user generates a mouse event. It can appear intermittent because the
invalid pixel geometry and the mouse input must coincide.

Minimal reproduction

from textual._xterm_parser import XTermParser


parser = XTermParser()

# Simulate a terminal that supports pixel mouse reporting and has valid
# character-cell dimensions, but does not provide pixel dimensions.
parser.mouse_pixels = True
parser.terminal_size = (80, 24)
parser.terminal_pixel_size = (0, 0)

# An ordinary SGR mouse-button event at cell/pixel coordinate 1,1.
parser.parse_mouse_code("\x1b[<0;1;1M")

Run with:

python mre.py

Actual behavior

Traceback (most recent call last):
  File "mre.py", line 13, in <module>
    parser.parse_mouse_code("\x1b[<0;1;1M")
  File ".../textual/_xterm_parser.py", line 93, in parse_mouse_code
    x /= x_ratio
ZeroDivisionError: float division by zero

This was reproduced with Textual 8.2.3. The original application report was
from Textual 6.8.0 and failed in the same method.

A zero pixel_height with a nonzero pixel_width similarly fails at
y /= y_ratio.

Expected behavior

A zero or otherwise invalid pixel size should be treated as unavailable.
Textual should either:

  • retain the mouse coordinates without pixel-to-cell conversion, or
  • discard the mouse event if it cannot be interpreted reliably.

It should not terminate the input thread.

Possible fix

Validate all dimensions before calculating the ratios:

if (
    self.mouse_pixels
    and self.terminal_pixel_size is not None
    and self.terminal_size is not None
):
    pixel_width, pixel_height = self.terminal_pixel_size
    width, height = self.terminal_size

    if min(pixel_width, pixel_height, width, height) > 0:
        x_ratio = pixel_width / width
        y_ratio = pixel_height / height
        x /= x_ratio
        y /= y_ratio

Alternatively, zero-valued pixel dimensions could be normalized to None
when resize events are ingested. A consumer-side validation still seems useful
as defensive protection against invalid geometry from any driver or in-band
resize report.

Textual Diagnostics

❯ textual diagnose

Textual Diagnostics

Versions

Name Value
Textual 8.2.8
Rich 15.0.0

Python

Name Value
Version 3.14.7
Implementation CPython
Compiler GCC 15.3.0
Executable /home/tom/Projects/rode/workspace/.devenv/state/venv/bin/python3.14

Operating System

Name Value
System Linux
Release 7.2.2
Version #1-NixOS SMP PREEMPT_DYNAMIC Fri Aug 28 06:25:22 UTC 2026

Terminal

Name Value
Terminal Application Alacritty
TERM alacritty
COLORTERM truecolor
FORCE_COLOR Not set
NO_COLOR Not set

Rich Console options

Name Value
size width=139, height=58
legacy_windows False
min_width 1
max_width 139
is_terminal True
encoding utf-8
max_height 58
justify None
overflow None
no_wrap False
highlight None
markup None
height None

Additional context

The original failure occurred under Linux and Python 3.14 in
LinuxDriver._run_input_thread():

LinuxDriver.run_input_thread()
  -> XTermParser.feed()
  -> XTermParser.parse()
  -> XTermParser.parse_mouse_code()
  -> x /= x_ratio
  -> ZeroDivisionError

The application itself does not handle mouse events directly. Moving, clicking,
or scrolling the mouse is only the immediate trigger; the invalid zero-valued
pixel geometry is the underlying cause.

Checklist

  • I searched open and closed issues for parse_mouse_code, x_ratio,
    terminal_pixel_size, and ZeroDivisionError, and did not find a duplicate.
  • The minimal reproduction below runs without modification.
  • The issue reproduces on a recent Textual release.

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