{"record":{"id":"f987e5c3a2a33a8f","repo":"apache/beam","slug":"escapechar-must-be-bytes-of-size-1-s","errorCode":null,"errorMessage":"escapechar must be bytes of size 1: '%s'","messagePattern":"escapechar must be bytes of size 1: '(.+?)'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/textio.py","lineNumber":170,"sourceCode":"    self._buffer_size = buffer_size\n    if skip_header_lines < 0:\n      raise ValueError(\n          'Cannot skip negative number of header lines: %d' % skip_header_lines)\n    elif skip_header_lines > 10:\n      _LOGGER.warning(\n          'Skipping %d header lines. Skipping large number of header '\n          'lines might significantly slow down processing.')\n    self._skip_header_lines = skip_header_lines\n    self._header_matcher, self._header_processor = header_processor_fns\n    if delimiter is not None:\n      if not isinstance(delimiter, bytes) or len(delimiter) == 0:\n        raise ValueError('Delimiter must be a non-empty bytes sequence.')\n      if self._is_self_overlapping(delimiter):\n        raise ValueError('Delimiter must not self-overlap.')\n    self._delimiter = delimiter\n    if escapechar is not None:\n      if not (isinstance(escapechar, bytes) and len(escapechar) == 1):\n        raise ValueError(\n            \"escapechar must be bytes of size 1: '%s'\" % escapechar)\n    self._escapechar = escapechar\n\n  def display_data(self):\n    parent_dd = super().display_data()\n    parent_dd['strip_newline'] = DisplayDataItem(\n        self._strip_trailing_newlines, label='Strip Trailing New Lines')\n    parent_dd['buffer_size'] = DisplayDataItem(\n        self._buffer_size, label='Buffer Size')\n    parent_dd['coder'] = DisplayDataItem(self._coder.__class__, label='Coder')\n    return parent_dd\n\n  def read_records(self, file_name, range_tracker):\n    start_offset = range_tracker.start_position()\n    read_buffer = _TextSource.ReadBuffer(b'', 0)\n\n    next_record_start_position = -1\n","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/textio.py#L152-L188","documentation":"The text/batch reader validates its CSV escapechar option: Python's csv module requires escapechar to be a one-byte string, so anything longer (or of another type) is rejected at constructor time as unusable for delimiter escaping.","triggerScenarios":"Passing escapechar='\\\\' (str) instead of b'\\\\', or a multi-byte bytes value like b'\\\\\\\\', or None-like sequences of wrong length.","commonSituations":"Python 3 str-vs-bytes confusion when configuring quote/escape behavior for CSV-style sources.","solutions":["Pass a single-byte bytes value, e.g. escapechar=b'\"' or escapechar=b'\\\\'","Encode a str char: escapechar=c.encode('ascii') ensuring len == 1","Pass escapechar=None if no escaping is needed"],"exampleFix":"// before\nReadFromText('gs://bucket/f', escapechar='\\\\')\n// after\nReadFromText('gs://bucket/f', escapechar=b'\\\\')","handlingStrategy":"validation","validationCode":"if escapechar is not None and (not isinstance(escapechar, bytes) or len(escapechar) != 1):\n    raise ValueError('escapechar must be a single byte, got %r' % (escapechar,))","typeGuard":"def is_valid_escapechar(c) -> bool:\n    return c is None or (isinstance(c, bytes) and len(c) == 1)","tryCatchPattern":"try:\n    src = ReadFromText(path, escapechar=esc)\nexcept ValueError as e:\n    if 'escapechar' in str(e):\n        esc = esc.encode('ascii') if isinstance(esc, str) and len(esc) == 1 else None\n        src = ReadFromText(path, escapechar=esc)\n    else:\n        raise","preventionTips":["Use bytes literals for escapechar: b'\\\\' or b'\"'","Never pass multi-byte escape sequences; escape handling is byte-wise","Pass None explicitly when escaping is not needed"],"tags":["python","beam","io","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}