{"record":{"id":"631eb78f99786d26","repo":"ruvnet/RuView","slug":"sync-packet-too-short-len-raw-data-bytes-need","errorCode":null,"errorMessage":"Sync packet too short: {len(raw_data)} bytes, need {cls.SIZE}","messagePattern":"Sync packet too short: (.+?) bytes, need (.+?)","errorType":"exception","errorClass":"CSIParseError","httpStatus":null,"severity":"error","filePath":"archive/v1/src/hardware/csi_extractor.py","lineNumber":357,"sourceCode":"\n        magic = struct.unpack_from('<I', data, 0)[0]\n        if magic == ESP32BinaryParser.MAGIC:    # 0xC5110001 — CSI frame\n            ...\n        elif magic == SyncPacketParser.MAGIC:   # 0xC511A110 — sync packet\n            ...\n    \"\"\"\n\n    MAGIC = 0xC511A110\n    SIZE = 32\n    # <IBBBB QQ IB3x>\n    # I=magic, B=node_id, B=proto_ver, B=flags, B=reserved,\n    # Q=local_us, Q=epoch_us, I=sequence, B+3x=reserved\n    HEADER_FMT = '<IBBBBQQI4x'\n\n    @classmethod\n    def parse(cls, raw_data: bytes) -> SyncPacket:\n        if len(raw_data) < cls.SIZE:\n            raise CSIParseError(\n                f\"Sync packet too short: {len(raw_data)} bytes, need {cls.SIZE}\"\n            )\n        magic, node_id, proto_ver, flags_byte, _, local_us, epoch_us, seq = \\\n            struct.unpack_from(cls.HEADER_FMT, raw_data, 0)\n        if magic != cls.MAGIC:\n            raise CSIParseError(f\"Sync magic mismatch: got 0x{magic:08x}\")\n        return SyncPacket(\n            node_id=node_id,\n            proto_ver=proto_ver,\n            is_leader=bool(flags_byte & 0x01),\n            is_valid=bool(flags_byte & 0x02),\n            smoothed_used=bool(flags_byte & 0x04),\n            local_us=local_us,\n            epoch_us=epoch_us,\n            sequence=seq,\n            flags_raw=flags_byte,\n        )\n","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/archive/v1/src/hardware/csi_extractor.py#L339-L375","documentation":"SyncPacketParser.parse requires at least 32 bytes (SIZE=32, HEADER_FMT '<IBBBBQQI4x': magic, node_id, proto_ver, flags, reserved, local_us, epoch_us, sequence) and raises CSIParseError naming both the received and required lengths otherwise. These 32-byte sync packets (magic 0xC511A110) are emitted every CONFIG_C6_SYNC_EVERY_N_FRAMES frames by firmware v0.6.9+ on the same UDP socket as CSI frames.","triggerScenarios":"parse() on a buffer holding fewer than 32 bytes; a truncated datagram; reading a TCP-style byte stream with a fixed read size that splits a packet; mixing sync and CSI bytes in one buffer and slicing incorrectly.","commonSituations":"Collector assuming one-read-per-packet on a stream transport when sync packets are UDP datagrams; buffer drained before being filled; probing the parser with short test bytes.","solutions":["Treat each UDP datagram as exactly one sync packet: skip/log datagrams whose length is not 32 instead of parsing","If buffering a byte stream, accumulate until at least 32 bytes and split on the sync magic","Verify firmware v0.6.9+ so sync packets actually use this 32-byte layout"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"SIZE = SyncPacketParser.SIZE  # 32\n\nif len(datagram) < SIZE:\n    logger.debug('short sync datagram (%d bytes), skipping', len(datagram))\n    continue\nsync = SyncPacketParser.parse(datagram)","typeGuard":null,"tryCatchPattern":"try:\n    sync = SyncPacketParser.parse(pkt)\nexcept CSIParseError as e:\n    logger.debug('dropping malformed sync packet: %s', e)","preventionTips":["Handle each UDP datagram as exactly one 32-byte sync packet; skip datagrams of any other length","When buffering a byte stream, fill to at least 32 bytes and split on the sync magic before parsing","Confirm firmware v0.6.9+ (ADR-110) so sync packets use the documented 32-byte layout"],"tags":["sync","binary","framing","adr-110","parsing"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}