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 HzView on GitHub (pinned to 4685618388)
Solutions
- Guard before parsing: only call parse when raw_data is truthy (see validationCode)
- Treat b'' as a control signal: on timeout continue the loop, on EOF reconnect or stop the stream
- 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
- Check truthiness of every read result before handing it to a parser — b'' is a timeout/EOF signal, not data
- Use readline-style, newline-delimited reads so empty reads are unambiguous control events
- Distinguish retryable empty reads (timeout) from terminal ones (EOF/closed socket) in the capture loop
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
- Failed to parse ESP32 data: {e}
- Invalid ESP32 CSI data format
- ESP32 CSI data incomplete: expected {expected_values} values
- ESP32 CSI data contains non-numeric values: {ve}. Raw CSI fi
- Frame too short: need {self.HEADER_SIZE} bytes, got {len(raw
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/8f4f843801a395a4.
Report an issue: GitHub.