ruvnet/RuView · error · CSIParseError

Empty data received

Error message

Empty data received

What it means

First guard in ESP32CSIParser.parse: falsy raw_data (b'', empty bytearray, None) is rejected with CSIParseError('Empty data received') before any decoding. The parser only accepts complete text frames, so zero bytes means the caller's read produced nothing — serial timeout, closed socket/EOF, or a polling loop that raced the producer.

Source

Thrown at archive/v1/src/hardware/csi_extractor.py:69


class ESP32CSIParser:
    """Parser for ESP32 CSI data format."""
    
    def parse(self, raw_data: bytes) -> CSIData:
        """Parse ESP32 CSI data format.
        
        Args:
            raw_data: Raw bytes from ESP32
            
        Returns:
            Parsed CSI data
            
        Raises:
            CSIParseError: If data format is invalid
        """
        if not raw_data:
            raise CSIParseError("Empty data received")
        
        try:
            data_str = raw_data.decode('utf-8')
            if not data_str.startswith('CSI_DATA:'):
                raise CSIParseError("Invalid ESP32 CSI data format")
            
            # Parse ESP32 format: CSI_DATA:timestamp,antennas,subcarriers,freq,bw,snr,[amp],[phase]
            parts = data_str[9:].split(',')  # Remove 'CSI_DATA:' prefix
            
            timestamp_ms = int(parts[0])
            num_antennas = int(parts[1])
            num_subcarriers = int(parts[2])
            frequency_mhz = float(parts[3])
            bandwidth_mhz = float(parts[4])
            snr = float(parts[5])
            
            # Convert to proper units
            frequency = frequency_mhz * 1e6  # MHz to Hz

View on GitHub (pinned to 4685618388)

Solutions

  1. Guard before parsing: only call parse when raw_data is truthy (see validationCode)
  2. Treat b'' as a control signal: on timeout continue the loop, on EOF reconnect or stop the stream
  3. Use newline-delimited reads (readline) with a timeout sized to the CSI frame interval so empty reads are rare

Example fix

# before
frame = ser.readline()
data = parser.parse(frame)  # CSIParseError when readline() timed out

# after
frame = ser.readline()
if not frame:
    continue  # timeout or EOF: retry / handle disconnect
frame = frame.strip()
if frame.startswith(b'CSI_DATA:'):
    data = parser.parse(frame)
Defensive patterns

Strategy: validation

Validate before calling

frame = ser.readline()
if not frame:
    continue  # read timeout or EOF: nothing to parse
data = parser.parse(frame)

Try / catch

from src.hardware.csi_extractor import CSIParseError

try:
    data = parser.parse(frame)
except CSIParseError as e:
    logger.debug('skipping unparseable frame: %s', e)
    continue

Prevention

When it happens

Trigger: parser.parse(ser.readline()) where pyserial returned b'' because timeout elapsed; parse(reader.read(1024)) at stream EOF; parse(None) from an uninitialized buffer; feeding the parser from a queue that yielded an empty payload.

Common situations: pyserial loops with timeout= set (b'' is the timeout signal, not an error); ESP32 node rebooting and dropping the TCP/UDP connection; replaying a capture file and running past the last line.

Related errors


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