Textualize/rich · error · ValueError
level must be 'head', 'row' or 'foot'
Error message
level must be 'head', 'row' or 'foot'
What it means
Box.row (the method that renders one horizontal rule of a box character set) only accepts level values "head", "row", "mid", or "foot"; anything else raises ValueError("level must be 'head', 'row' or 'foot'"). This is essentially an internal API used by Table rendering — the error message even forgets to mention the accepted "mid" level. End users normally never call it directly.
Source
Thrown at rich/box.py:150
cross = self.head_row_cross
right = self.head_row_right
elif level == "row":
left = self.row_left
horizontal = self.row_horizontal
cross = self.row_cross
right = self.row_right
elif level == "mid":
left = self.mid_left
horizontal = " "
cross = self.mid_vertical
right = self.mid_right
elif level == "foot":
left = self.foot_row_left
horizontal = self.foot_row_horizontal
cross = self.foot_row_cross
right = self.foot_row_right
else:
raise ValueError("level must be 'head', 'row' or 'foot'")
parts: List[str] = []
append = parts.append
if edge:
append(left)
for last, width in loop_last(widths):
append(horizontal * width)
if not last:
append(cross)
if edge:
append(right)
return "".join(parts)
def get_bottom(self, widths: Iterable[int]) -> str:
"""Get the bottom of a simple box.
Args:
widths (List[int]): Widths of columns.View on GitHub (pinned to 9d8f9a372c)
Solutions
- Pass one of "head", "row", "mid", or "foot" as the level
- If you don't need a semantic row type, use the default (typically "row")
- Prefer composing boxes via the predefined box constants (box.SQUARE, box.DOUBLE, ...) rather than calling Box.row yourself
Example fix
// before (Python) sep = box.SQUARE.row([], widths, level="header") # ValueError // after sep = box.SQUARE.row([], widths, level="head")
Defensive patterns
Strategy: validation
Validate before calling
if level not in ("head", "row", "mid", "foot"):
raise ValueError(f"invalid box level {level!r}")
line = box.SQUARE.row(characters, widths, level=level) Type guard
from typing import Literal, TypeGuard
def is_box_level(v: object) -> TypeGuard[str]:
return v in ("head", "row", "mid", "foot") Prevention
- Treat Box.row as a semi-internal API; prefer the predefined box constants
- Note the accepted set includes 'mid' even though the error message omits it
- Centralize any direct Box.row calls in one wrapper you can test
When it happens
Trigger: Calling box.SQUARE.row(head_row, widths, level=...) with a misspelled or unknown level string; custom Table/box subclasses or plugins that invoke Box.row directly with their own level names; passing None or an empty string.
Common situations: Almost exclusively seen when writing custom table renderers or third-party extensions that reuse Box.row; occasionally triggered by copying example code that hardcodes an invalid level.
Related errors
- invalid value for align, expected "left", "center", or "righ
- invalid value for vertical, expected "top", "middle", or "bo
- {original_color!r} is not a valid color
- color number must be <= 255 in {color!r}
- expected three components in {original_color!r}
AI-assisted analysis of Textualize/rich@9d8f9a372c (2026-08-15).
Data as JSON: /api/errors/da741d623d7f922e.
Report an issue: GitHub.