donnemartin/interactive-coding-challenges · error · ValueError

num cannot be negative

Error message

num cannot be negative

What it means

Solution.add_digits raises ValueError('num cannot be negative') because digit extraction via % and // does not represent negative numbers meaningfully in this implementation. The guard runs after the None check, so negative input is explicitly rejected rather than looping forever or producing wrong digit sums.

Source

Thrown at math_probability/add_digits/add_digits_solution.ipynb:101

   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Solution(object):\n",
    "\n",
    "    def add_digits(self, num):\n",
    "        if num is None:\n",
    "            raise TypeError('num cannot be None')\n",
    "        if num < 0:\n",
    "            raise ValueError('num cannot be negative')\n",
    "        digits = []\n",
    "        while num != 0:\n",
    "            digits.append(num % 10)\n",
    "            num //= 10\n",
    "        digits_sum = sum(digits)\n",
    "        if digits_sum >= 10:\n",
    "            return self.add_digits(digits_sum)\n",
    "        else:\n",
    "            return digits_sum\n",
    "\n",
    "    def add_digits_optimized(self, num):\n",
    "        if num is None:\n",
    "            raise TypeError('num cannot be None')\n",
    "        if num < 0:\n",
    "            raise ValueError('num cannot be negative')\n",
    "        if num == 0:\n",
    "            return 0\n",
    "        elif num % 9 == 0:\n",

View on GitHub (pinned to 358f2cc604)

Solutions

  1. Pass abs(num) if the sign is irrelevant to your use case
  2. Clamp or validate at the boundary: reject negatives before calling add_digits
  3. Catch ValueError when negatives are expected but should be skipped

Example fix

// before
result = solution.add_digits(delta)  # ValueError if delta < 0
// after
result = solution.add_digits(abs(delta))
Defensive patterns

Strategy: validation

Validate before calling

num = abs(num) if allow_negative else num
if num < 0:
    raise ValueError('num must be non-negative')
solution.add_digits(num)

Type guard

def is_non_negative_int(num) -> bool:
    return isinstance(num, int) and num >= 0

Try / catch

try:
    result = solution.add_digits(num)
except ValueError:
    result = solution.add_digits(abs(num))

Prevention

When it happens

Trigger: Calling add_digits(-5), add_digits(-100), or passing a computed value that can go negative (e.g. a difference or delta) without clamping.

Common situations: Reusing the routine on differences/offsets that dip below zero; feeding raw signed integers from financial or sensor data; porting code that assumed abs() was applied upstream.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of donnemartin/interactive-coding-challenges@358f2cc604 (2026-08-28). Data as JSON: /api/errors/8e09c2fea0a00fd3. Report an issue: GitHub.