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
- Clamp or reject negatives at the boundary: `if n < 0: raise/input again` before calling
- Fix the caller's arithmetic (k - 1 with k == 0 usually means the loop bound or edge case is wrong)
- 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
- Prefer math.factorial in production code; validate n >= 0 at input boundaries
- Audit k - 1 style index math for k == 0 edge cases
- Reject negative user input where it enters the program, not deep in math helpers
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
- mod inverse of {a!r} and {m!r} does not exist
- surface_area_cube() only accepts non-negative values
- surface_area_cuboid() only accepts non-negative values
- surface_area_sphere() only accepts non-negative values
- surface_area_hemisphere() only accepts non-negative values
AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14).
Data as JSON: /api/errors/372f5062015db478.
Report an issue: GitHub.