TheAlgorithms/Python · error · ValueError

vol_icosahedron() only accepts non-negative values

Error message

vol_icosahedron() only accepts non-negative values

What it means

Raised by vol_icosahedron(tri_side) in maths/volume.py when the triangle edge length is negative. The function returns tri_side**3 * (3 + sqrt(5)) * 5 / 12 after the guard; tri_side == 0 is valid and returns 0.0.

Source

Thrown at maths/volume.py:539

    >>> isclose(vol_icosahedron(10), 2181.694990624912374)
    True
    >>> isclose(vol_icosahedron(5), 272.711873828114047)
    True
    >>> isclose(vol_icosahedron(3.49), 92.740688412033628)
    True
    >>> vol_icosahedron(0)
    0.0
    >>> vol_icosahedron(-1)
    Traceback (most recent call last):
        ...
    ValueError: vol_icosahedron() only accepts non-negative values
    >>> vol_icosahedron(-0.2)
    Traceback (most recent call last):
        ...
    ValueError: vol_icosahedron() only accepts non-negative values
    """
    if tri_side < 0:
        raise ValueError("vol_icosahedron() only accepts non-negative values")
    return tri_side**3 * (3 + 5**0.5) * 5 / 12


def main():
    """Print the Results of Various Volume Calculations."""
    print("Volumes:")
    print(f"Cube: {vol_cube(2) = }")  # = 8
    print(f"Cuboid: {vol_cuboid(2, 2, 2) = }")  # = 8
    print(f"Cone: {vol_cone(2, 2) = }")  # ~= 1.33
    print(f"Right Circular Cone: {vol_right_circ_cone(2, 2) = }")  # ~= 8.38
    print(f"Prism: {vol_prism(2, 2) = }")  # = 4
    print(f"Pyramid: {vol_pyramid(2, 2) = }")  # ~= 1.33
    print(f"Sphere: {vol_sphere(2) = }")  # ~= 33.5
    print(f"Hemisphere: {vol_hemisphere(2) = }")  # ~= 16.75
    print(f"Circular Cylinder: {vol_circular_cylinder(2, 2) = }")  # ~= 25.1
    print(f"Torus: {vol_torus(2, 2) = }")  # ~= 157.9
    print(f"Conical Frustum: {vol_conical_frustum(2, 2, 4) = }")  # ~= 58.6
    print(f"Spherical cap: {vol_spherical_cap(1, 2) = }")  # ~= 5.24

View on GitHub (pinned to f5988cc097)

Solutions

  1. Validate tri_side >= 0 before the call; reject negative lengths at input parsing with your own message.
  2. Replace sentinel defaults (-1 meaning 'unset') with None and check for them explicitly.
  3. Convert signed vector differences to magnitudes (abs or norm) before using as edge lengths.

Example fix

# before
side = row.get('edge', -1)  # -1 sentinel
vol = vol_icosahedron(side)  # ValueError when row missing

# after
side = row.get('edge')
if side is None or side < 0:
    raise ValueError(f"invalid edge length in row: {side!r}")
vol = vol_icosahedron(side)
Defensive patterns

Strategy: type-guard

Validate before calling

def is_valid_edge(side) -> bool:
    return isinstance(side, (int, float)) and not isinstance(side, bool) and side >= 0

Type guard

def is_valid_edge(side) -> TypeGuard[float]:
    return isinstance(side, (int, float)) and not isinstance(side, bool) and side >= 0

Try / catch

try:
    v = vol_icosahedron(side)
except ValueError as e:
    raise ValueError(f'edge length must be >= 0, got {side}') from e

Prevention

When it happens

Trigger: Calling vol_icosahedron(-1) or vol_icosahedron(-0.2); edge lengths from user input or mesh data with a negative sign.

Common situations: Parsing edge lengths from strings like '-0.2'; direction-signed edge vectors used directly as lengths; default sentinel values of -1 leaking into geometry calls.

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/f04b895b987fb326. Report an issue: GitHub.