donnemartin/interactive-coding-challenges · error · ValueError

Invalid arg: x1 or x2 out of bounds

Error message

Invalid arg: x1 or x2 out of bounds

What it means

BitsScreen.draw_line raises ValueError when x1 or x2 falls outside the screen: negative, or >= len(screen) * 8 (the total number of bits available). This bounds check runs after the None and empty-input checks.

Source

Thrown at bit_manipulation/draw_line/draw_line_solution.ipynb:166

    "## Code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "class BitsScreen(object):\n",
    "\n",
    "    def draw_line(self, screen, width, x1, x2):\n",
    "        if None in (screen, width, x1, x2):\n",
    "            raise TypeError('Invalid argument: None')\n",
    "        if not screen or not width:\n",
    "            raise ValueError('Invalid arg: Empty screen or width')\n",
    "        MAX_BIT_VALUE = len(screen) * 8\n",
    "        if x1 < 0 or x2 < 0 or x1 >= MAX_BIT_VALUE or x2 >= MAX_BIT_VALUE:\n",
    "            raise ValueError('Invalid arg: x1 or x2 out of bounds')\n",
    "        start_bit = x1 % 8\n",
    "        end_bit = x2 % 8\n",
    "        first_full_byte = x1 // 8\n",
    "        if start_bit != 0:\n",
    "            first_full_byte += 1\n",
    "        last_full_byte = x2 // 8\n",
    "        if end_bit != (8 - 1):\n",
    "            last_full_byte -= 1\n",
    "        for byte in range(first_full_byte, last_full_byte + 1):\n",
    "            screen[byte] = int('11111111', base=2)\n",
    "        start_byte = x1 // 8\n",
    "        end_byte = x2 // 8\n",
    "        if start_byte == end_byte:\n",
    "            left_mask = (1 << (8 - start_bit)) - 1\n",
    "            right_mask = ~((1 << (8 - end_bit - 1)) - 1)\n",
    "            mask = left_mask & right_mask\n",
    "            screen[start_byte] |= mask\n",
    "        else:\n",

View on GitHub (pinned to 358f2cc604)

Solutions

  1. Clamp coordinates: x = max(0, min(x, len(screen) * 8 - 1))
  2. Fix off-by-one: use x2 = width - 1, not width
  3. Verify coordinate space (bits, not bytes/pixels) matches the API expectation

Example fix

# before
bits.draw_line(screen, 16, 0, 16)  # 2-byte screen, 16 is out of bounds

# after
bits.draw_line(screen, 16, 0, 15)
Defensive patterns

Strategy: validation

Validate before calling

max_bit = len(screen) * 8
x1, x2 = max(0, x1), max(0, x2)
if x1 >= max_bit or x2 >= max_bit:
    raise ValueError(f'coordinates must be < {max_bit}')
bits_screen.draw_line(screen, width, x1, x2)

Type guard

def in_bounds(screen, x) -> bool:
    return 0 <= x < len(screen) * 8

Try / catch

try:
    bits_screen.draw_line(screen, width, x1, x2)
except ValueError as e:
    if 'out of bounds' in str(e):
        x2 = min(x2, len(screen) * 8 - 1)
        bits_screen.draw_line(screen, width, x1, x2)
    else:
        raise

Prevention

When it happens

Trigger: draw_line(screen, 8, -1, 4), or draw_line(screen, 8, 0, 8) on a 1-byte screen where MAX_BIT_VALUE is 8 and x2 == 8; also passing pixel coordinates where the code expects bit coordinates.

Common situations: Confusing width with total bit capacity, off-by-one at the right edge (x2 == MAX_BIT_VALUE instead of MAX_BIT_VALUE - 1), or reusing coordinates from a larger screen on a smaller buffer.

Related errors


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