Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python asyncio byte frames: reject an oversized length before reading a body

Last updated: 1 Oct 20265 min read
tutorial
IntermediateBy AITrove Editorial

A length-prefixed stream needs a maximum body size and an explicit short-read path.

Download Python source kit

Operation contract

The parser consumes a two-byte unsigned length, rejects a declared body over its eight-byte limit, and then reads exactly that many bytes. One owned frame completes; another ends after five of its seven promised bytes. The partial payload is treated as a failed record, never as a shorter accepted record.

Failure boundary

StreamReader.feed_data is used only to supply controlled bytes without opening a socket. A real peer can pause forever between bytes, so a caller also needs a deadline and a connection cleanup policy. The length check bounds one returned body; it does not cap the total bytes a transport may have buffered before parsing begins.

Working program

python
import asyncio

async def read_receipt_frame(reader, maximum_body):
    header = await reader.readexactly(2)
    body_size = int.from_bytes(header, "big")
    if body_size > maximum_body:
        raise ValueError("receipt body too large")
    return await reader.readexactly(body_size)

async def inspect_frames():
    complete = asyncio.StreamReader()
    complete.feed_data((7).to_bytes(2, "big") + b"R47paid")
    complete.feed_eof()
    print("accepted", (await read_receipt_frame(complete, 8)).decode("ascii"))

    oversized = asyncio.StreamReader()
    oversized.feed_data((73).to_bytes(2, "big"))
    oversized.feed_eof()
    try:
        await read_receipt_frame(oversized, 8)
    except ValueError:
        print("oversized_rejected", True)

    shortened = asyncio.StreamReader()
    shortened.feed_data((7).to_bytes(2, "big") + b"R73pa")
    shortened.feed_eof()
    try:
        await read_receipt_frame(shortened, 8)
    except asyncio.IncompleteReadError as failure:
        print("partial_rejected", failure.partial == b"R73pa")

asyncio.run(inspect_frames())

Output

Output
accepted R47paid
oversized_rejected True
partial_rejected True

Costs and limits

Header parsing is constant work; copying a valid body costs time and memory proportional to its declared size. A maximum body of eight bytes is a fixture policy, not a network-wide memory budget.

Common Mistakes

  • read(n) may return fewer than n bytes without EOF; use readexactly for a fixed frame.
  • Reject the declared length before allocating or awaiting its body.
  • An incomplete read is a failed frame even when partial bytes exist.

Connected lessons

Test this contract.

python
async-length-prefixed-frame
Storage details