TryBugHunt

Off-by-one errors in Python and JavaScript

The loop that runs one time too many, the slice that drops the last item, the index that starts in the wrong place.

26 free challenges17 Python9 JavaScript

What is an off-by-one error?

An off-by-one error is a loop bound, index or count that is wrong by exactly one. The logic is right; the arithmetic is one step out. They are among the most common bugs in programming precisely because they hide so well — the code produces almost the right answer, which is far harder to notice than no answer at all.

Why it happens

Almost every off-by-one comes from mixing two counting conventions in the same expression. Array indices start at 0 but lengths start at 1. Python's range() and JavaScript's slice() exclude their upper bound, while a phrase like "items 1 to 10" includes both ends. Whenever those conventions meet without a deliberate conversion, something ends up one out.

How to recognise it

  • The result is right except for the first or last element.
  • A sum comes out as NaN in JavaScript, because reading past the end gave undefined.
  • IndexError in Python at exactly the final iteration.
  • It works for even-sized input and breaks for odd, or vice versa.

Error guides caused by this pattern

All error guides →

In-depth guides for common exceptions and runtime errors triggered by off-by-one errors, with working fixes and real-world examples:

How to fix it

Test the smallest case by hand. A list of length n has indices 0 to n-1; a window of size k fits n - k + 1 times; n items need n - 1 separators. Write the boundary case as a test before you write the loop, because the boundary is exactly where these live and exactly what casual testing skips.

Breaks vs Works Example

Breaks

# Python: loop attempts to index past the end
for i in range(len(items) + 1):
    print(items[i])  # IndexError: list index out of range

Works

# Python: exclusive upper bound stops at len(items) - 1
for i in range(len(items)):
    print(items[i])  # or simply: for item in items

💡 Array indices run from 0 to n-1. In JavaScript, use 'i < arr.length', not 'i <= arr.length'.

Practise off-by-one errors

Working code with one bug in it. Find it, fix it in the browser, and see the explanation. No account needed.

javascriptEasy
Score total skips the first round

totalScore(rounds) adds up the points from every round. Example: totalScore([10, 20, 30]) → 60.

Off-by-one

pythonEasy
Shopping total crashes at the end of the list

cart_total(prices) adds up every price. Example: cart_total([10, 20, 30]) → 60.

Off-by-one

javascriptEasy
Capitalize turns "debug" into "Ddebug"

capitalize(word) makes the first letter a capital. Example: capitalize("debug") → "Debug".

Off-by-one

pythonEasy
Comparing each day with the next crashes at the end

count_rises(prices) counts the days a price went up from the day before. Example: count_rises([3, 5, 4, 6]) → 2.

Off-by-one

pythonEasy
Countdown never reaches zero

countdown(n) returns the numbers from n down to 0. Example: countdown(3) → [3, 2, 1, 0].

Off-by-one

pythonEasy
Preview cuts off one letter too soon

preview(text, length) returns the first length characters. Example: preview("Hello world", 5) → "Hello".

Off-by-one

pythonEasy
Shopping list numbering starts at 0

numbered(items) numbers the list starting from 1. Example: numbered(["eggs", "milk"]) → ["1. eggs", "2. milk"].

Off-by-one

pythonEasy
Last letter crashes with IndexError

last_char(text) returns the last character. Example: last_char("hello") → "o".

Off-by-one

pythonEasy
Staircase pattern starts with an empty step

stairs(n) builds a staircase of n steps. Example: stairs(3) → ["#", "##", "###"].

Off-by-one

javascriptEasy
Playlist shows undefined as the last song

lastSong(playlist) returns the last song. Example: lastSong(["Intro", "Hook", "Outro"]) → "Outro".

Off-by-one

javascriptEasy
First 3 items comes back with only 2

firstChunk(arr, size) returns the first size items of the array. Example: firstChunk([1, 2, 3, 4, 5], 3) → [1, 2, 3].

Off-by-one

pythonEasy
Sum from 1 to n leaves out n

sum_range(n) adds up every whole number from 1 to n. Example: sum_range(5) → 15 (1 + 2 + 3 + 4 + 5).

Off-by-one

javascriptEasy
Adding up [1, 2, 3] gives NaN

sumAll(nums) adds up every number in the array. Example: sumAll([1, 2, 3]) → 6.

Off-by-one

pythonHard
Best window of 2 misses the last pair

max_window_sum(nums, k) returns the biggest sum of k numbers in a row. Example: max_window_sum([1, 2, 3, 10], 2) → 13 (3 + 10).

Off-by-one

javascriptHard
Page 1 shows the second page of items

pageItems(items, page, size) returns one page of items. Pages start at 1. Example: pageItems([1, 2, 3, 4, 5, 6], 1, 3) → [1, 2, 3].

Off-by-one

pythonHard
Binary search can't find the last item

binary_search(nums, target) returns the index of target in a sorted list, or -1 if it is not there. Example: binary_search([1, 3, 5, 7, 9], 9) → 4.

Off-by-one

pythonHard
Splitting into groups loses the last group

chunk(items, size) splits a list into groups of size, and keeps a shorter last group. Example: chunk([1, 2, 3, 4, 5], 2) → [[1, 2], [3, 4], [5]].

Off-by-one

pythonMedium
AI Attempt: The missing number finder

An AI assistant wrote this for a classic interview question. nums has every number from 1 to n except one. missing_number(nums, n) returns the missing one. Example: missing_number([1, 2, 4], 4) → 3.

Off-by-one

pythonMedium
Range count skips the lowest value

count_in_range(nums, low, high) counts the values from low to high, including both ends. Example: count_in_range([1, 2, 3], 1, 3) → 3.

Off-by-one

pythonMedium
Last 3 letters comes back with 4

last_n_chars(text, n) returns the last n characters of text. Example: last_n_chars("debugging", 3) → "ing".

Off-by-one

javascriptMedium
Every date shows last month

formatDate(isoDate) turns a date like "2024-03-15" into "15/3/2024". Example: formatDate("2024-03-15") → "15/3/2024".

Off-by-one

pythonMedium
Leave calculator counts one day short

leave_days(start_iso, end_iso) counts the days of leave, including the first and last day. Example: leave_days("2024-01-01", "2024-01-07") → 7.

Off-by-one

javascriptMedium
Last 2 items comes back with 3

getLastNItems(arr, n) returns the last n items of the array. Example: getLastNItems([1, 2, 3, 4, 5], 2) → [4, 5].

Off-by-one

pythonMedium
Swapping rows and columns drops a column

transpose(grid) swaps rows and columns. Example: transpose([[1, 2, 3], [4, 5, 6]]) → [[1, 4], [2, 5], [3, 6]].

Off-by-one

pythonMedium
AI Attempt: Fibonacci starts one step ahead

An AI assistant wrote this for a recursion exercise. fib(n) returns the nth number in 0, 1, 1, 2, 3, 5, 8 … Example: fib(0) → 0, fib(1) → 1, fib(6) → 8.

Off-by-one

javascriptMedium
Joining words leaves a dash at the end

joinWithDash(words) joins the words with a dash between each pair. Example: joinWithDash(["a", "b"]) → "a-b".

Off-by-one

Stuck on your own code?

Paste it into the visualizer and watch it run line by line, with every variable at every step. Free, and it runs in your browser.

Other bug patterns