ruvnet/RuView · error · CSIParseError

Sync magic mismatch: got 0x{magic:08x}

Error message

Sync magic mismatch: got 0x{magic:08x}

What it means

After the length check, SyncPacketParser validates the first dword against magic 0xC511A110 and raises CSIParseError('Sync magic mismatch: got 0x...') on mismatch. The 32 bytes came from a source that is not an ADR-110 sync packet — most often an ADR-018 CSI frame (magic 0xC5110001) routed to the wrong parser, or a desynced stream window.

Source

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

    """

    MAGIC = 0xC511A110
    SIZE = 32
    # <IBBBB QQ IB3x>
    # I=magic, B=node_id, B=proto_ver, B=flags, B=reserved,
    # Q=local_us, Q=epoch_us, I=sequence, B+3x=reserved
    HEADER_FMT = '<IBBBBQQI4x'

    @classmethod
    def parse(cls, raw_data: bytes) -> SyncPacket:
        if len(raw_data) < cls.SIZE:
            raise CSIParseError(
                f"Sync packet too short: {len(raw_data)} bytes, need {cls.SIZE}"
            )
        magic, node_id, proto_ver, flags_byte, _, local_us, epoch_us, seq = \
            struct.unpack_from(cls.HEADER_FMT, raw_data, 0)
        if magic != cls.MAGIC:
            raise CSIParseError(f"Sync magic mismatch: got 0x{magic:08x}")
        return SyncPacket(
            node_id=node_id,
            proto_ver=proto_ver,
            is_leader=bool(flags_byte & 0x01),
            is_valid=bool(flags_byte & 0x02),
            smoothed_used=bool(flags_byte & 0x04),
            local_us=local_us,
            epoch_us=epoch_us,
            sequence=seq,
            flags_raw=flags_byte,
        )


class RouterCSIParser:
    """Parser for router CSI data format."""
    
    def parse(self, raw_data: bytes) -> CSIData:
        """Parse router CSI data format.

View on GitHub (pinned to 4685618388)

Solutions

  1. Dispatch on magic, not length: peek the first 4 bytes — 0xC5110001 goes to the CSI parser, 0xC511A110 to the sync parser, anything else is dropped/resynced
  2. If streams are interleaved, resync by scanning for the magic dword
  3. Log the received magic: 0xC5110001 confirms a routing bug; random garbage confirms desync

Example fix

# before
if len(pkt) == 32:
    sync = SyncPacketParser.parse(pkt)  # may be a 32-byte-aligned CSI fragment

# after
import struct
magic = struct.unpack_from('<I', pkt, 0)[0] if len(pkt) >= 4 else 0
if magic == SyncPacketParser.MAGIC:
    sync = SyncPacketParser.parse(pkt)
elif magic == ESP32BinaryParser.MAGIC:
    frame = ESP32BinaryParser().parse(pkt)
Defensive patterns

Strategy: validation

Validate before calling

import struct

def peek_magic(buf: bytes) -> int:
    return struct.unpack_from('<I', buf, 0)[0] if len(buf) >= 4 else 0

magic = peek_magic(pkt)
if magic == SyncPacketParser.MAGIC:
    sync = SyncPacketParser.parse(pkt)
elif magic == ESP32BinaryParser.MAGIC:
    frame = ESP32BinaryParser().parse(pkt)
else:
    drop_or_resync(pkt)

Type guard

def is_sync_packet(buf: bytes) -> bool:
    import struct
    return len(buf) >= 32 and struct.unpack_from('<I', buf, 0)[0] == SyncPacketParser.MAGIC

Try / catch

try:
    sync = SyncPacketParser.parse(pkt)
except CSIParseError as e:
    if 'Sync magic mismatch' in str(e):
        logger.warning('wrong packet routed to sync parser; re-dispatch by magic')
    raise

Prevention

When it happens

Trigger: Dispatching a CSI frame buffer to SyncPacketParser.parse; a 32-byte window cut mid-stream that starts inside a packet; the wrong socket's data fed to the sync parser.

Common situations: Both frame types share one UDP socket in node deployments; naive length-based dispatch ('32 bytes must be a sync packet') colliding with short or garbled frames; version skew where an older firmware emits a different sync layout.

Related errors


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