{"record":{"id":"9f61f2bd90864989","repo":"TheAlgorithms/Python","slug":"next-side-must-be-a-side-or-none","errorCode":null,"errorMessage":"next_side must be a Side or None.","messagePattern":"next_side must be a Side or None\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"geometry/geometry.py","lineNumber":75,"sourceCode":"        ...\n    TypeError: angle must be an Angle object.\n    >>> Side(5, Angle(90), \"Invalid next_side\")\n    Traceback (most recent call last):\n        ...\n    TypeError: next_side must be a Side or None.\n    \"\"\"\n\n    length: float\n    angle: Angle = field(default_factory=Angle)\n    next_side: Side | None = None\n\n    def __post_init__(self) -> None:\n        if not isinstance(self.length, (int, float)) or self.length <= 0:\n            raise TypeError(\"length must be a positive numeric value.\")\n        if not isinstance(self.angle, Angle):\n            raise TypeError(\"angle must be an Angle object.\")\n        if not isinstance(self.next_side, (Side, NoneType)):\n            raise TypeError(\"next_side must be a Side or None.\")\n\n\n@dataclass\nclass Ellipse:\n    \"\"\"\n    A geometric Ellipse on a 2D surface\n\n    >>> Ellipse(5, 10)\n    Ellipse(major_radius=5, minor_radius=10)\n    >>> Ellipse(5, 10) is Ellipse(5, 10)\n    False\n    >>> Ellipse(5, 10) == Ellipse(5, 10)\n    True\n    \"\"\"\n\n    major_radius: float\n    minor_radius: float\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/TheAlgorithms/Python/blob/f5988cc09713315817df6a7e327e258013a94440/geometry/geometry.py#L57-L93","documentation":"Raised by Side.__post_init__ (geometry/geometry.py:75) when next_side is neither a Side instance nor None. next_side is used to chain sides into a polygon outline, so the type must be exactly Side or None (checked against (Side, NoneType)).","triggerScenarios":"Passing a number, tuple, or list as next_side, e.g. Side(5, next_side=7) or Side(5, next_side=(3, Angle(45))). Also passing a subclass-like duck type that is not an actual Side.","commonSituations":"Building polygons programmatically and passing a coordinate tuple instead of the next Side; deserializing polygon data where next_side arrives as a dict; assuming any object with length/angle attributes would be accepted (structural typing is not used here).","solutions":["Pass None (the default) when there is no successor: Side(5)","Construct the next Side first, then link: second = Side(3); first = Side(5, next_side=second)","When deserializing, rebuild the Side chain from raw data with a small loader function instead of feeding raw dicts/tuples to the dataclass"],"exampleFix":"# before\nside = Side(5, next_side=(3, Angle(45)))\n\n# after\nside = Side(5, next_side=Side(3, angle=Angle(45)))","handlingStrategy":"type-guard","validationCode":"from geometry.geometry import Side\n\nnext_side = None if raw_next is None else raw_next\nassert next_side is None or isinstance(next_side, Side)\nside = Side(length, angle=angle, next_side=next_side)","typeGuard":"def is_side_or_none(value: object) -> bool:\n    from geometry.geometry import Side\n    return value is None or isinstance(value, Side)","tryCatchPattern":null,"preventionTips":["Build side chains with a loop that only links Side objects","Never pass raw tuples/dicts as next_side; convert in a loader"],"tags":["geometry","type-validation","dataclass"],"backgroundTag":null,"analyzedSha":"f5988cc09713315817df6a7e327e258013a94440","analyzedAt":"2026-08-14T17:30:07.041Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}