{"record":{"id":"224ff4a924cff368","repo":"python/cpython","slug":"embedded-null-character","errorCode":null,"errorMessage":"embedded null character","messagePattern":"embedded null character","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pyrepl/readline.py","lineNumber":430,"sourceCode":"        pass  # XXX we don't support parsing GNU-readline-style init files\n\n    def set_completer(self, function: Completer | None = None) -> None:\n        self.config.readline_completer = function\n\n    def get_completer(self) -> Completer | None:\n        return self.config.readline_completer\n\n    def set_completer_delims(self, delimiters: Collection[str]) -> None:\n        self.config.completer_delims = frozenset(delimiters)\n\n    def get_completer_delims(self) -> str:\n        return \"\".join(sorted(self.config.completer_delims))\n\n    def _histline(self, line: str, *, sanitize_nuls: bool = False) -> str:\n        line = line.rstrip(\"\\n\")\n        if \"\\0\" in line:\n            if not sanitize_nuls:\n                raise ValueError(\"embedded null character\")\n            line = line.replace(\"\\0\", \"\")\n        return line\n\n    def get_history_length(self) -> int:\n        return self.saved_history_length\n\n    def set_history_length(self, length: int) -> None:\n        self.saved_history_length = length\n\n    def get_current_history_length(self) -> int:\n        return len(self.get_reader().history)\n\n    def read_history_file(self, filename: str = gethistoryfile()) -> None:\n        # multiline extension (really a hack) for the end of lines that\n        # are actually continuations inside a single multiline_input()\n        # history item: we use \\r\\n instead of just \\n.  If the history\n        # file is passed to GNU readline, the extra \\r are just ignored.\n        history = self.get_reader().history","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyrepl/readline.py#L412-L448","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nimport readline\nreadline.add_history(buf)  # ValueError if '\\0' in buf\n\n# after\nimport readline\nreadline.add_history(buf.replace('\\0', ''))","handlingStrategy":"validation","validationCode":"import readline\n\ndef add_history_safe(line):\n    if '\\0' in line:\n        line = line.replace('\\0', '')\n    readline.add_history(line)","typeGuard":null,"tryCatchPattern":"try:\n    readline.add_history(line)\nexcept ValueError as e:\n    if 'embedded null' in str(e):\n        readline.add_history(line.replace('\\0', ''))\n    else:\n        raise","preventionTips":["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."],"tags":["python","pyrepl","readline","history","null-byte"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}