StreamReader.readuntil raises on an overlong record without consuming its buffered bytes.
Python asyncio delimiter limits: an overrun leaves the bytes buffered
Operation contract
The owned reader has an eight-byte separator limit. Its first line is longer than that limit, so readuntil raises LimitOverrunError. The program reads the first ten retained bytes afterward to prove that the failed delimiter search did not consume the record. It does not silently rescan the same oversized line.
Failure boundary
The stream limit governs delimiter scanning, not the total memory already accepted by a transport. A service must decide whether to close the connection or drain a bounded amount after an overrun. This fixture chooses to stop; it is not a recovery parser for attacker-controlled streams.
Working program
import asyncio
async def inspect_delimiter_limit():
reader = asyncio.StreamReader(limit=8)
reader.feed_data(b"receipt-47-untrusted\n")
reader.feed_eof()
try:
await reader.readuntil(b"\n")
except asyncio.LimitOverrunError:
print("overrun_rejected", True)
retained_prefix = await reader.readexactly(10)
print("retained_prefix", retained_prefix.decode("ascii"))
asyncio.run(inspect_delimiter_limit())Output
overrun_rejected True
retained_prefix receipt-47Costs and limits
A delimiter scan examines bytes up to the limit before rejecting. Retained input still occupies memory until the connection owner consumes or discards it.
Common Mistakes
- Retrying readuntil unchanged after an overrun repeats the same failure.
- A separator limit is not a complete transport buffer budget.
- Do not accept an overlong prefix as a valid shortened record.
