python/cpython · error · ValueError
Separator should be at least one-byte string
Error message
Separator should be at least one-byte string
What it means
ValueError raised by StreamReader.readuntil() when the shortest separator is a zero-length bytes object (min_seplen == 0). A zero-length separator would match everywhere and make the consume-buffer arithmetic (which reserves max_seplen - 1 bytes) degenerate, so it is rejected upfront.
Source
Thrown at Lib/asyncio/streams.py:613
will be left in the internal buffer, so it can be read again.
The ``separator`` may also be a tuple of separators. In this
case the return value will be the shortest possible that has any
separator as the suffix. For the purposes of LimitOverrunError,
the shortest possible separator is considered to be the one that
matched.
"""
if isinstance(separator, tuple):
# Makes sure shortest matches wins
separator = sorted(separator, key=len)
else:
separator = [separator]
if not separator:
raise ValueError('Separator should contain at least one element')
min_seplen = len(separator[0])
max_seplen = len(separator[-1])
if min_seplen == 0:
raise ValueError('Separator should be at least one-byte string')
if self._exception is not None:
raise self._exception
# Consume whole buffer except last bytes, which length is
# one less than max_seplen. Let's check corner cases with
# separator[-1]='SEPARATOR':
# * we have received almost complete separator (without last
# byte). i.e buffer='some textSEPARATO'. In this case we
# can safely consume max_seplen - 1 bytes.
# * last byte of buffer is first byte of separator, i.e.
# buffer='abcdefghijklmnopqrS'. We may safely consume
# everything except that last byte, but this require to
# analyze bytes of buffer that match partial separator.
# This is slow and/or require FSM. For this case our
# implementation is not optimal, since require rescanning
# of data that is known to not belong to separator. In
# real world, separator will not be so long to noticeView on GitHub (pinned to bc6749cc3b)
Solutions
- Filter empty separators out of the collection before calling readuntil
- Validate delimiter strings at the API/config boundary: must be non-empty bytes
- If you intended an any-position single-byte match, iterate bytes manually or use read() and buffer splitting yourself
Example fix
// before
seps = tuple(d.encode() for d in delims) # may contain b''
line = await reader.readuntil(seps)
// after
seps = tuple(d.encode() for d in delims if d)
if not seps:
raise ValueError('at least one non-empty delimiter required')
line = await reader.readuntil(seps) Defensive patterns
Strategy: validation
Validate before calling
def checked_separator(sep: bytes) -> bytes:
if not isinstance(sep, (bytes, bytearray)) or len(sep) == 0:
raise ValueError(f'separator must be non-empty bytes, got {sep!r}')
return bytes(sep) Type guard
null
Try / catch
null
Prevention
- Reject empty delimiters wherever delimiters enter the system (CLI, config, protocol negotiation)
- Remember readuntil accepts bytes, not str — encode first
When it happens
Trigger: await reader.readuntil(b''), or readuntil((b'', b'\n')) where sorting by length puts the empty separator first; also a tuple containing an empty element after dynamic construction.
Common situations: Splitting user-supplied input on a delimiter where the user passed an empty string; separator lists assembled from parsed headers (e.g. an empty value for one terminator); copy-paste of str.split-style habits where '' is tolerated.
Related errors
- Separator should contain at least one element
- Limit cannot be <= 0
- readexactly size can not be less than zero
- Unimplemented ioctl request
- profiling_trace: Placeholder pattern not found in {js_path.n
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/fde9faf9f2e3e4a8.
Report an issue: GitHub.