{"record":{"id":"6effd6223f1c56fe","repo":"ruvnet/RuView","slug":"esp32-csi-data-incomplete-expected-expected-valu","errorCode":null,"errorMessage":"ESP32 CSI data incomplete: expected {expected_values} values (amplitude + phase for {num_antennas} antennas x {num_subcarriers} subcarriers), but received {len(data_values)} values. Ensure the ESP32 firmware is configured to output full CSI matrix data. See docs/hardware-setup.md for ESP32 CSI configuration.","messagePattern":"ESP32 CSI data incomplete: expected (.+?) values \\(amplitude \\+ phase for (.+?) antennas x (.+?) subcarriers\\), but received (.+?) values\\. Ensure the ESP32 firmware is configured to output full CSI matrix data\\. See docs/hardware-setup\\.md for ESP32 CSI configuration\\.","errorType":"exception","errorClass":"CSIExtractionError","httpStatus":null,"severity":"error","filePath":"archive/v1/src/hardware/csi_extractor.py","lineNumber":97,"sourceCode":"            timestamp_ms = int(parts[0])\n            num_antennas = int(parts[1])\n            num_subcarriers = int(parts[2])\n            frequency_mhz = float(parts[3])\n            bandwidth_mhz = float(parts[4])\n            snr = float(parts[5])\n            \n            # Convert to proper units\n            frequency = frequency_mhz * 1e6  # MHz to Hz\n            bandwidth = bandwidth_mhz * 1e6  # MHz to Hz\n            \n            # Parse amplitude and phase arrays from the remaining CSV fields.\n            # Expected format after the header fields: comma-separated float values\n            # representing interleaved amplitude and phase per antenna per subcarrier.\n            data_values = parts[6:]\n            expected_values = num_antennas * num_subcarriers * 2  # amplitude + phase\n\n            if len(data_values) < expected_values:\n                raise CSIExtractionError(\n                    f\"ESP32 CSI data incomplete: expected {expected_values} values \"\n                    f\"(amplitude + phase for {num_antennas} antennas x {num_subcarriers} subcarriers), \"\n                    f\"but received {len(data_values)} values. \"\n                    \"Ensure the ESP32 firmware is configured to output full CSI matrix data. \"\n                    \"See docs/hardware-setup.md for ESP32 CSI configuration.\"\n                )\n\n            try:\n                float_values = [float(v) for v in data_values[:expected_values]]\n            except ValueError as ve:\n                raise CSIExtractionError(\n                    f\"ESP32 CSI data contains non-numeric values: {ve}. \"\n                    \"Raw CSI fields must be numeric float values.\"\n                )\n\n            all_values = np.array(float_values)\n            amplitude = all_values[:num_antennas * num_subcarriers].reshape(num_antennas, num_subcarriers)\n            phase = all_values[num_antennas * num_subcarriers:].reshape(num_antennas, num_subcarriers)","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/archive/v1/src/hardware/csi_extractor.py#L79-L115","documentation":"Raised when the CSV payload after the six header fields contains fewer than num_antennas * num_subcarriers * 2 values: the parser needs interleaved amplitude+phase for every antenna x subcarrier cell. Note it raises CSIExtractionError, not CSIParseError — a distinct class despite sitting in the same parse path. The message reports expected vs received counts and points to docs/hardware-setup.md.","triggerScenarios":"Firmware printing amplitude-only CSI (half the expected values); header claiming antennas=2 while the payload carries one antenna's matrix; a truncated serial line losing trailing fields; extra/missing commas shifting field count.","commonSituations":"Using stock esp32-csi-tool example firmware that outputs amplitude only; CONFIG subcarrier count disagreeing with the printed header; locale or firmware-version drift changing how many values per line are emitted.","solutions":["Flash/configure the ESP32 firmware to output the full interleaved amplitude+phase matrix per docs/hardware-setup.md","Pre-check arity before parsing: after the 6 header fields there must be at least 2 * antennas * subcarriers values (see validationCode)","If only amplitude-only firmware is available, switch to the ADR-018 binary format (parser_format='binary') or extend the parser — never pad phase with zeros silently"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"def has_full_matrix(line: str) -> bool:\n    parts = line.strip()[len('CSI_DATA:'):].split(',')\n    if len(parts) < 7:\n        return False\n    try:\n        n_ant, n_sub = int(parts[1]), int(parts[2])\n    except ValueError:\n        return False\n    return len(parts) - 6 >= n_ant * n_sub * 2\n\nif not has_full_matrix(line):\n    logger.error('firmware emitted short CSI row; check amplitude+phase output')","typeGuard":null,"tryCatchPattern":"from src.hardware.csi_extractor import CSIParseError, CSIExtractionError\n\ntry:\n    data = parser.parse(raw)\nexcept CSIExtractionError as e:  # NOTE: not CSIParseError\n    logger.error('incomplete CSI payload (firmware config): %s', e)\n    raise\nexcept CSIParseError as e:\n    logger.debug('dropping malformed line: %s', e)","preventionTips":["Verify firmware emits interleaved amplitude+phase (2 values per antenna x subcarrier) before deploying the collector","Remember the class split: incomplete/non-numeric payloads raise CSIExtractionError while header/protocol problems raise CSIParseError — catch both explicitly","Log the raw line on failure; the expected-vs-received counts in the message identify exactly which matrix dimension is short"],"tags":["esp32","firmware","csi","parsing","data-quality"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}