aio-libs/aiohttp · error · ValueError
Separator should be at least one-byte string
Error message
Separator should be at least one-byte string
What it means
Raised by StreamReader.readuntil when the separator has length 0. readuntil scans the buffer for the separator, so an empty separator is meaningless (every position matches). aiohttp validates len(separator) == 0 and raises ValueError rather than returning the entire buffer. The default separator is b'\n' so this only fires when the caller explicitly passes b''.
Source
Thrown at aiohttp/streams.py:386
self._waiter = None
async def _fire_chunk_received(self, chunk: bytes) -> None:
cb = self._on_chunk_received
assert cb is not None
# Run under the same per-stream timer that _wait() uses, so a hung
# trace handler is bounded by sock_read just like a hung socket read would be.
with self._timer:
await cb(chunk)
async def readline(self, *, max_line_length: int | None = None) -> bytes:
return await self.readuntil(max_size=max_line_length)
async def readuntil(
self, separator: bytes = b"\n", *, max_size: int | None = None
) -> bytes:
seplen = len(separator)
if seplen == 0:
raise ValueError("Separator should be at least one-byte string")
if self._exception is not None:
raise self._exception
chunk = b""
chunk_size = 0
not_enough = True
max_size = max_size or self._high_water
while not_enough:
while self._buffer and not_enough:
offset = self._buffer_offset
ichar = self._buffer[0].find(separator, offset) + 1
# Read from current offset to found separator or to the end.
data = self._read_nowait_chunk(
ichar - offset + seplen - 1 if ichar else -1
)
chunk += dataView on GitHub (pinned to c0ef574e29)
Solutions
- Pass a non-empty bytes separator (default b'\n' is usually what you want for line reads).
- If you genuinely want everything, use await request.content.read(-1) instead of readuntil(b'').
- Validate the separator before calling: `if not sep: raise ValueError(...)`.
Example fix
// before
line = await request.content.readuntil(sep) # sep may be b''
// after
if not sep:
raise ValueError('separator must be non-empty')
line = await request.content.readuntil(sep) Defensive patterns
Strategy: validation
Validate before calling
def safe_readuntil(stream, sep):
if not isinstance(sep, (bytes, bytearray)) or len(sep) == 0:
raise ValueError('separator must be non-empty bytes')
return stream.readuntil(bytes(sep)) Try / catch
try:
line = await stream.readuntil(sep)
except ValueError as e:
if 'Separator should be' in str(e):
raise ValueError('provide a non-empty separator') from e
raise Prevention
- Always validate separator length at the call site.
- Default to b'\n' unless you need a different delimiter.
- Use read(-1) for un-delimited bulk reads.
When it happens
Trigger: Calling await request.content.readuntil(b'') or request.content.readline(max_line_length=...) after monkey-patching the separator to empty; passing a computed separator that resolves to b'' due to a bug (e.g. separator = prefix[len(prefix):]).
Common situations: Programmatic separator derived from user input that can be empty; copy-paste from readuntil docs where the default was overridden; trying to use readuntil as a non-delimited bulk read.
Related errors
- module {__name__} has no attribute {name}
- Compress wbits must between 9 and 15, zlib does not support
- base_url must have a trailing '/'
- data and json parameters can not be used at the same time
- None is not allowed as login value
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/f5694f28c7ed0fcd.json.
Report an issue: GitHub.