ruvnet/RuView · error · ValueError

Insufficient data for header

Error message

Insufficient data for header

What it means

ValueError from AtherosCSIFormat.parse_header when the byte buffer is shorter than HEADER_SIZE (25). The Atheros CSI header (timestamp, channel, rate, RSSI, noise, antenna config, CSI length, MAC) is unpacked unconditionally from data[:25], so anything shorter cannot contain a valid header.

Source

Thrown at plans/phase2-architecture/hardware-integration.md:353

    # Packet structure
    HEADER_SIZE = 25  # bytes
    
    # Header format (little-endian)
    # Offset | Size | Field
    # 0      | 8    | Timestamp (microseconds)
    # 8      | 2    | Channel
    # 10     | 2    | Rate
    # 12     | 1    | RSSI
    # 13     | 1    | Noise
    # 14     | 1    | Antenna config
    # 15     | 2    | CSI length
    # 17     | 8    | MAC address
    
    @staticmethod
    def parse_header(data):
        """Parse Atheros CSI packet header"""
        if len(data) < AtherosCSIFormat.HEADER_SIZE:
            raise ValueError("Insufficient data for header")
        
        header = struct.unpack('<QHHBBHQ', data[:25])
        
        return {
            'timestamp': header[0],
            'channel': header[1],
            'rate': header[2],
            'rssi': header[3] - 256 if header[3] > 127 else header[3],
            'noise': header[4] - 256 if header[4] > 127 else header[4],
            'antenna_config': header[5],
            'csi_length': header[6],
            'mac_address': header[7]
        }
    
    @staticmethod
    def parse_csi_data(data, header):
        """Parse CSI complex values"""
        csi_start = AtherosCSIFormat.HEADER_SIZE

View on GitHub (pinned to 4685618388)

Solutions

  1. Buffer incoming bytes and only call parse_header once at least HEADER_SIZE (25) bytes are available
  2. If reading from a stream, add explicit framing (length-prefix) or use the CSI length field plus header size to consume whole packets
  3. If the stream is desynchronized, resync by scanning for a plausible header instead of parsing at the current offset
  4. Drop and count undersized datagrams with a warning rather than crashing the capture loop

Example fix

# before
header = AtherosCSIFormat.parse_header(buf)  # ValueError when len(buf) < 25

# after
if len(buf) < AtherosCSIFormat.HEADER_SIZE:
    buf += read_more()          # accumulate until a full header is buffered
header = AtherosCSIFormat.parse_header(buf)
Defensive patterns

Strategy: validation

Validate before calling

if len(buf) < AtherosCSIFormat.HEADER_SIZE:  # 25 bytes
    buf += read_more()  # accumulate; do not parse partial headers
header = AtherosCSIFormat.parse_header(buf)

Type guard

def has_full_header(buf: bytes) -> bool:
    return len(buf) >= AtherosCSIFormat.HEADER_SIZE

Try / catch

try:
    header = AtherosCSIFormat.parse_header(chunk)
except ValueError as e:
    if 'Insufficient data for header' in str(e):
        buffer.extend(chunk)  # re-buffer and wait for more bytes
        continue
    raise

Prevention

When it happens

Trigger: Feeding parse_header a truncated read: a stream socket (TCP/file) read returned fewer than 25 bytes; a UDP datagram got clipped; or the parser was called on a buffer that is mid-packet because packet framing was lost.

Common situations: Reading /tmp/csi.dat-style captures with a fixed read size that splits packets; socket recv() returning partial payloads; test fixtures built from too-small samples; off-by-one framing after a dropped packet desynchronizes the byte stream.

Related errors


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/05d96a98aec58735. Report an issue: GitHub.