ValueError: list.remove(x): x not in list (tested fix)
ValueError: list.remove(x): x not in list means no element of the list equals the value you passed. list.index() raises the same error as 'x' is not in list. We reproduced both in Python 3.13 and tested the fixes.
1. The value is not in the list (exactly)
list.remove() and list.index() look for an element that is equal to the argument. If there isn't one, they raise ValueError. The two methods word the error differently, and a case or whitespace difference counts as "not in list":
items = ["a", "b", "c"]
for call in ['items.remove("z")', 'items.index("z")', 'items.remove("A")', 'items.remove(" b")']:
try:
eval(call)
except ValueError as e:
print(f"{call:20} ValueError: {e}")
Output:
items.remove("z") ValueError: list.remove(x): x not in list
items.index("z") ValueError: 'z' is not in list
items.remove("A") ValueError: list.remove(x): x not in list
items.remove(" b") ValueError: list.remove(x): x not in list
2. The fix: check with in, or catch ValueError
items = ["a", "b", "c"]
if "z" in items: # check first
items.remove("z")
try: # or ask forgiveness
items.remove("z")
except ValueError:
pass
print(items)
i = items.index("z") if "z" in items else -1 # list has no .find()
print(i)
Output:
['a', 'b', 'c']
-1
Lists have no .find() returning -1 the way strings do, so write the conditional yourself.
3. remove() only removes the first match
nums = [1, 2, 2, 3, 2]
nums.remove(2) # removes only the FIRST match
print(nums)
nums = [1, 2, 2, 3, 2]
print([n for n in nums if n != 2]) # remove ALL matches
nums = [1, 2, 2, 3]
for n in nums: # removing while looping skips items
if n == 2:
nums.remove(n)
print(nums)
Output:
[1, 2, 3, 2]
[1, 3]
[1, 2, 3]
To drop every occurrence, build a new list with a comprehension. Removing items while looping over the same list skips the element after each removal, so one 2 survives in the last line.
4. The usual hidden cause: "2" vs 2, or a trailing newline
ids = [1, 2, 3]
try:
ids.remove("2") # str from input() / CSV / JSON key vs int
except ValueError as e:
print("ValueError:", e)
ids.remove(int("2"))
print(ids)
words = ["Apple\n", "Pear\n"] # lines read from a file keep the newline
try:
words.remove("Apple")
except ValueError as e:
print("ValueError:", e)
words = [w.strip() for w in words]
words.remove("Apple")
print(words)
Output:
ValueError: list.remove(x): x not in list
[1, 3]
ValueError: list.remove(x): x not in list
['Pear']
Values from input(), CSV files and query strings are strings, so they never equal ints in your list. Lines read from a file keep their \n. Convert or strip() before you compare.
5. Removing by index, and other containers
nums = [1, 2, 3, 2]
print(nums.pop(1), nums) # remove by index (IndexError if out of range)
del nums[0]; print(nums)
s = {1, 2, 3}
s.discard(9) # sets: discard never raises
print(s)
try:
s.remove(9)
except KeyError as e:
print("set.remove -> KeyError:", e)
import collections
d = collections.deque([1, 2])
try:
d.remove(9)
except ValueError as e:
print("deque -> ValueError:", e)
Output:
2 [1, 3, 2]
[3, 2]
{1, 2, 3}
set.remove -> KeyError: 9
deque -> ValueError: 9 is not in deque
Use pop(i) or del to remove by position. For sets, discard() is the no-error version; set.remove() raises KeyError, not ValueError. deque.remove() raises ValueError with its own wording. See also Python ValueError and list index out of range.
Frequently asked questions
How do I remove an item from a list without an error if it's missing?
Check first with if x in items: items.remove(x), or wrap remove() in try/except ValueError.
Why does remove() say not in list when I can see the value?
It is usually a type or whitespace mismatch: '2' vs 2, 'Apple\n' vs 'Apple', or different case.
How do I remove all occurrences of a value?
Build a new list: [x for x in items if x != value]. remove() only deletes the first match.
Written with AI assistance. Measured on 2026-10-22 on Debian with Python 3.13.5: list.remove and list.index misses, first-match-only removal, str vs int and newline mismatches, pop/del, set.discard and deque.remove. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.