python/cpython · error · ValueError
No history item at position %d
Error message
No history item at position %d
What it means
ValueError from remove_history_item in Lib/_pyrepl/readline.py. Unlike get_history_item, which uses readline's 1-based convention, remove_history_item indexes the reader's history list 0-based and requires 0 <= index < len(history). Any out-of-range index raises 'No history item at position %d', mirroring GNU readline's error.
Source
Thrown at Lib/_pyrepl/readline.py:513
f.write(entry + "\n")
self.set_history_length(saved_length + length)
def clear_history(self) -> None:
del self.get_reader().history[:]
def get_history_item(self, index: int) -> str | None:
history = self.get_reader().history
if 1 <= index <= len(history):
return history[index - 1]
else:
return None # like readline.c
def remove_history_item(self, index: int) -> None:
history = self.get_reader().history
if 0 <= index < len(history):
del history[index]
else:
raise ValueError("No history item at position %d" % index)
# like readline.c
def replace_history_item(self, index: int, line: str) -> None:
history = self.get_reader().history
if 0 <= index < len(history):
history[index] = self._histline(line)
else:
raise ValueError("No history item at position %d" % index)
# like readline.c
def add_history(self, line: str) -> None:
self.get_reader().history.append(self._histline(line))
def set_startup_hook(self, function: Callback | None = None) -> None:
self.startup_hook = function
def get_line_buffer(self) -> str:
return self.get_reader().get_unicode()View on GitHub (pinned to bc6749cc3b)
Solutions
- Use 0-based indices and clamp to current length: 0 <= i < readline.get_current_history_length().
- When deleting multiple items, delete from the end downward (for i in range(n-1, -1, -1)) so indices stay valid, or re-read the length each iteration.
- Remember the asymmetry: get_history_item is 1-based, remove/replace are 0-based — same as GNU readline.
Example fix
# before
for i in range(1, readline.get_current_history_length()):
readline.remove_history_item(i) # ValueError on later iterations
# after
for i in range(readline.get_current_history_length() - 1, -1, -1):
readline.remove_history_item(i) Defensive patterns
Strategy: validation
Validate before calling
import readline
def remove_history_safe(i):
if 0 <= i < readline.get_current_history_length():
readline.remove_history_item(i)
else:
raise ValueError(f'no history item {i}') Prevention
- remove/replace are 0-based; only get_history_item is 1-based.
- Delete from the end downward when clearing history.
- Re-read length each iteration in mutating loops.
When it happens
Trigger: readline.remove_history_item(i) with i >= len(history) or i < 0. Classic trap: iterating with 1-based indices taken from get_current_history_length() or code written against get_history_item's 1-based API.
Common situations: Porting readline C or ctypes code that mixes 1-based and 0-based conventions; popping history entries in a loop with a stale length after each removal (length shrinks as you delete); off-by-one when deleting the last item (index == length).
Related errors
- embedded null character
- Windows 10 TH2 or later required
- \C must be followed by `-' (char %d of %s)
- doubled \C- (char %d of %s)
- \M must be followed by `-' (char %d of %s)
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/1c370c4cc91ae551.
Report an issue: GitHub.