ruvnet/RuView · error · CSIParseError

Failed to parse ESP32 data: {e}

Error message

Failed to parse ESP32 data: {e}

What it means

Catch-all at the end of ESP32CSIParser.parse: any ValueError or IndexError raised while reading the six header fields (timestamp, antennas, subcarriers, frequency, bandwidth, snr) is re-raised as CSIParseError('Failed to parse ESP32 data: ...'). IndexError means the line had fewer than seven comma-separated fields; ValueError means a header field failed int()/float().

Source

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

            all_values = np.array(float_values)
            amplitude = all_values[:num_antennas * num_subcarriers].reshape(num_antennas, num_subcarriers)
            phase = all_values[num_antennas * num_subcarriers:].reshape(num_antennas, num_subcarriers)
            
            return CSIData(
                timestamp=datetime.fromtimestamp(timestamp_ms / 1000, tz=timezone.utc),
                amplitude=amplitude,
                phase=phase,
                frequency=frequency,
                bandwidth=bandwidth,
                num_subcarriers=num_subcarriers,
                num_antennas=num_antennas,
                snr=snr,
                metadata={'source': 'esp32', 'raw_length': len(raw_data)}
            )
            
        except (ValueError, IndexError) as e:
            raise CSIParseError(f"Failed to parse ESP32 data: {e}")


class ESP32BinaryParser:
    """Parser for ADR-018 binary CSI frames from ESP32 nodes.

    Binary frame format:
        Offset  Size  Field
        0       4     Magic: 0xC5110001 (LE)
        4       1     Node ID
        5       1     Number of antennas
        6       2     Number of subcarriers (LE u16)
        8       4     Frequency MHz (LE u32)
        12      4     Sequence number (LE u32)
        16      1     RSSI (i8)
        17      1     Noise floor (i8)
        18      1     PPDU type (ADR-110): 0=HT/legacy, 1=HE-SU, 2=HE-MU,
                       3=HE-TB, 0xFF=unknown. Pre-ADR-110 firmware sends 0.
        19      1     Flags (ADR-110): bit 0 = bw40, bit 2 = STBC,

View on GitHub (pinned to 4685618388)

Solutions

  1. Read newline-delimited lines (readline / splitlines) so parse always receives a complete row
  2. Pre-validate the header: split(',') must yield at least 7 fields and fields 0-5 must be numeric (see validationCode)
  3. Keep firmware and pipeline versions in lockstep so the CSI_DATA header layout matches
Defensive patterns

Strategy: try-catch

Validate before calling

def looks_like_esp32_header(line: bytes) -> bool:
    parts = line.strip().split(b',')
    if len(parts) < 7 or not line.startswith(b'CSI_DATA:'):
        return False
    try:
        [int(parts[0]), int(parts[1]), int(parts[2])]
        [float(parts[3]), float(parts[4]), float(parts[5])]
    except ValueError:
        return False
    return True

Try / catch

try:
    data = parser.parse(raw)
except CSIParseError as e:
    logger.debug('dropping partial/malformed CSI line: %s (raw=%r)', e, raw[:80])

Prevention

When it happens

Trigger: 'CSI_DATA:123' or 'CSI_DATA:123,1,52' (IndexError: <7 fields); a non-numeric header field like 'CSI_DATA:ts,1,52,2437,20,31,...' (ValueError on int('ts')); a partial line delivered by a fixed-size chunked read.

Common situations: Reading the stream in fixed-size chunks instead of newline-delimited lines, so parse receives a line cut in half; header layout changes between firmware versions; CR/LF artifacts producing empty header fields.

Understand the failure class

Related errors


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