{"record":{"id":"c638e107e8fc791f","repo":"Textualize/rich","slug":"invalid-value-for-vertical-expected-top-middl","errorCode":null,"errorMessage":"invalid value for vertical, expected \"top\", \"middle\", or \"bottom\" (not {vertical!r})","messagePattern":"invalid value for vertical, expected \"top\", \"middle\", or \"bottom\" \\(not (.+?)\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"rich/align.py","lineNumber":63,"sourceCode":"    \"\"\"\n\n    def __init__(\n        self,\n        renderable: \"RenderableType\",\n        align: AlignMethod = \"left\",\n        style: Optional[StyleType] = None,\n        *,\n        vertical: Optional[VerticalAlignMethod] = None,\n        pad: bool = True,\n        width: Optional[int] = None,\n        height: Optional[int] = None,\n    ) -> None:\n        if align not in (\"left\", \"center\", \"right\"):\n            raise ValueError(\n                f'invalid value for align, expected \"left\", \"center\", or \"right\" (not {align!r})'\n            )\n        if vertical is not None and vertical not in (\"top\", \"middle\", \"bottom\"):\n            raise ValueError(\n                f'invalid value for vertical, expected \"top\", \"middle\", or \"bottom\" (not {vertical!r})'\n            )\n        self.renderable = renderable\n        self.align = align\n        self.style = style\n        self.vertical = vertical\n        self.pad = pad\n        self.width = width\n        self.height = height\n\n    def __repr__(self) -> str:\n        return f\"Align({self.renderable!r}, {self.align!r})\"\n\n    @classmethod\n    def left(\n        cls,\n        renderable: \"RenderableType\",\n        style: Optional[StyleType] = None,","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/Textualize/rich/blob/9d8f9a372cc5916fd4781fec207ced7ddac2f08f/rich/align.py#L45-L81","documentation":"Align.__init__ validates the keyword-only vertical argument: it must be None or one of \"top\", \"middle\", \"bottom\", otherwise ValueError. Unlike align, vertical is optional and defaults to None (no vertical alignment). The literal \"middle\" is used here, not \"center\" — a common source of confusion since horizontal alignment uses \"center\".","triggerScenarios":"Calling Align(renderable, vertical=\"center\") (mixing up the horizontal term), vertical=\"top \" with stray whitespace, or passing an empty string instead of None. Passing a vertical value via unpacked kwargs from a settings dict is another common route.","commonSituations":"Developers writing vertical=\"center\" by analogy with align=\"center\"; config-driven layouts where \"center\" is used for both axes; forgetting that None (not \"\") disables vertical alignment.","solutions":["Use exactly \"top\", \"middle\", or \"bottom\" (note: \"middle\", not \"center\")","Omit the vertical argument or pass None if no vertical alignment is wanted","Normalize user config values (strip().lower()) before passing them in"],"exampleFix":"// before (Python)\nAlign(panel, vertical=\"center\")  # ValueError\n// after\nAlign(panel, vertical=\"middle\")  # or omit / pass None","handlingStrategy":"type-guard","validationCode":"vertical = None if raw in (None, \"\") else str(raw).strip().lower()\nif vertical is not None and vertical not in (\"top\", \"middle\", \"bottom\"):\n    raise ValueError(f\"vertical must be top/middle/bottom, got {raw!r}\")\nrender = Align(panel, vertical=vertical)","typeGuard":"from typing import Literal, TypeGuard\n\nVerticalAlignMethod = Literal[\"top\", \"middle\", \"bottom\"]\n\ndef is_vertical_align(v: object) -> TypeGuard[VerticalAlignMethod]:\n    return v in (\"top\", \"middle\", \"bottom\")","tryCatchPattern":null,"preventionTips":["Remember the asymmetry: horizontal is 'center', vertical is 'middle'","Use None to disable vertical alignment, never an empty string","Lint config files for allowed vertical values at startup"],"tags":["python","rich","align","vertical","validation","valueerror"],"backgroundTag":null,"analyzedSha":"9d8f9a372cc5916fd4781fec207ced7ddac2f08f","analyzedAt":"2026-08-15T03:30:11.781Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}