TheAlgorithms/Python · error · ValueError

factorial() not defined for negative values

Error message

factorial() not defined for negative values

What it means

Raised by factorial(n) in number_of_possible_binary_trees when n < 0. Factorial is undefined for negative integers, and this iterative implementation (result = 1; for i in range(1, n+1)) would silently return 1 for negative n without the guard, so the check is essential, not cosmetic. The message intentionally matches CPython's math.factorial error text.

Source

Thrown at data_structures/binary_tree/number_of_possible_binary_trees.py:74

    return binomial_coefficient(2 * node_count, node_count) // (node_count + 1)


def factorial(n: int) -> int:
    """
    Return the factorial of a number.
    :param n: Number to find the Factorial of.
    :return: Factorial of n.

    >>> import math
    >>> all(factorial(i) == math.factorial(i) for i in range(10))
    True
    >>> factorial(-5)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
        ...
    ValueError: factorial() not defined for negative values
    """
    if n < 0:
        raise ValueError("factorial() not defined for negative values")
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result


def binary_tree_count(node_count: int) -> int:
    """
    Return the number of possible of binary trees.
    :param n: number of nodes
    :return: Number of possible binary trees

    >>> binary_tree_count(5)
    5040
    >>> binary_tree_count(6)
    95040
    """
    return catalan_number(node_count) * factorial(node_count)

View on GitHub (pinned to f5988cc097)

Solutions

  1. Clamp or reject negatives at the boundary: `if n < 0: raise/input again` before calling
  2. Fix the caller's arithmetic (k - 1 with k == 0 usually means the loop bound or edge case is wrong)
  3. Use math.factorial for general use — same error, but you avoid shipping a hand-rolled loop

Example fix

# before
n = int(input())  # user types -3
factorial(n)  # ValueError

# after
n = max(0, int(input()))
factorial(n)
Defensive patterns

Strategy: validation

Validate before calling

if n < 0:
    raise ValueError(f'n must be >= 0, got {n}')
factorial(n)

Type guard

def is_non_negative_int(n: object) -> bool:
    return isinstance(n, int) and not isinstance(n, bool) and n >= 0

Try / catch

try:
    f = factorial(n)
except ValueError:
    f = 1  # or clamp: f = factorial(max(0, n))

Prevention

When it happens

Trigger: factorial(-5); binary_tree_count(node_count) with negative node_count (it calls catalan_number * factorial); computing n! from user input parsed as a negative number.

Common situations: Subtraction-based index math producing -1 (e.g. factorial(k - 1) with k == 0); unvalidated CLI input; reusing the helper for general combinatorics where args can go negative.

Related errors


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