python/cpython · error · ValueError
embedded null character
Error message
embedded null character
What it means
ValueError from ReaderHistory/_histline in Lib/_pyrepl/readline.py (the readline compatibility layer over pyrepl). History lines cannot contain NUL characters because the underlying history storage (mirroring GNU readline / libedit) treats them as terminators. When a line passed to add_history, replace_history_item, or internal history recording contains \0 and sanitize_nuls is False, this error is raised.
Source
Thrown at Lib/_pyrepl/readline.py:430
pass # XXX we don't support parsing GNU-readline-style init files
def set_completer(self, function: Completer | None = None) -> None:
self.config.readline_completer = function
def get_completer(self) -> Completer | None:
return self.config.readline_completer
def set_completer_delims(self, delimiters: Collection[str]) -> None:
self.config.completer_delims = frozenset(delimiters)
def get_completer_delims(self) -> str:
return "".join(sorted(self.config.completer_delims))
def _histline(self, line: str, *, sanitize_nuls: bool = False) -> str:
line = line.rstrip("\n")
if "\0" in line:
if not sanitize_nuls:
raise ValueError("embedded null character")
line = line.replace("\0", "")
return line
def get_history_length(self) -> int:
return self.saved_history_length
def set_history_length(self, length: int) -> None:
self.saved_history_length = length
def get_current_history_length(self) -> int:
return len(self.get_reader().history)
def read_history_file(self, filename: str = gethistoryfile()) -> None:
# multiline extension (really a hack) for the end of lines that
# are actually continuations inside a single multiline_input()
# history item: we use \r\n instead of just \n. If the history
# file is passed to GNU readline, the extra \r are just ignored.
history = self.get_reader().historyView on GitHub (pinned to bc6749cc3b)
Solutions
- Strip NULs before pushing to history: line.replace('\0', '') on the input string.
- If your tool intentionally tolerates them, call the internal API with sanitize_nuls=True where available (internal history recording path) rather than the public readline functions.
- Fix the upstream producer — a NUL in a command line almost always means a decoding/paste bug worth investigating.
Example fix
# before
import readline
readline.add_history(buf) # ValueError if '\0' in buf
# after
import readline
readline.add_history(buf.replace('\0', '')) Defensive patterns
Strategy: validation
Validate before calling
import readline
def add_history_safe(line):
if '\0' in line:
line = line.replace('\0', '')
readline.add_history(line) Try / catch
try:
readline.add_history(line)
except ValueError as e:
if 'embedded null' in str(e):
readline.add_history(line.replace('\0', ''))
else:
raise Prevention
- Strip NULs from any string captured from sockets/pastes before history calls.
- Treat a NUL in a command line as a symptom of an upstream decode bug.
- Wrap third-party readline shims with the sanitizer above.
When it happens
Trigger: Calling readline.add_history(line) or replacing a history item with a string containing '\0' (e.g. data read from a socket, binary-ish protocol text, or strings built with null padding); internal history append of a command line with an embedded NUL when sanitization is not enabled.
Common situations: RL-compat shims in tools like IPython/pgcli that push arbitrary captured input into history; pasting from terminals that emit NUL bytes; programs that store length-padded buffers and forget to strip trailing '\0's before adding to history.
Related errors
- No history item at position %d
- 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/224ff4a924cff368.
Report an issue: GitHub.