AprilNEA/OpenLogi · error

sanitized Bolt receiver identity is not 16-byte ASCII

Error message

sanitized Bolt receiver identity is not 16-byte ASCII

What it means

`derive_replay_route` rebuilds the concrete device route from sanitized audit data. For a Bolt route it reads the sanitized ReceiverUniqueId replacement, which must be exactly 16 ASCII bytes to form a valid receiver UID; otherwise the sanitized fixture data is malformed and the error is thrown.

Solutions

  1. Re-record the fixture so the sanitizer regenerates a valid 16-byte ASCII receiver UID
  2. Inspect the fixture's audit section and correct the ReceiverUniqueId replacement to exactly 16 ASCII bytes
  3. Regenerate sanitized identities via the openlogi-fixture synthetic identity policy instead of editing them manually

Example fix

// before (hand-edited audit)
"receiver_unique_id": "ABC123"            // 6 bytes
// after
"receiver_unique_id": "A1B2C3D4E5F6A7B8"   // 16 ASCII bytes
Defensive patterns

Strategy: validation

Validate before calling

fn valid_bolt_uid(v: &[u8]) -> bool { v.len() == 16 && v.is_ascii() }
// check before replaying a Bolt fixture
assert!(valid_bolt_uid(&audit.receiver_unique_id), "sanitized Bolt UID must be 16 ASCII bytes");

Type guard

fn valid_bolt_uid(v: &[u8]) -> bool {
    v.len() == 16 && v.is_ascii()
}

Prevention

When it happens

Trigger: Replaying a Bolt-routed fixture whose audit identity replacement for ReceiverUniqueId is missing, the wrong length (not 16 bytes), or contains non-ASCII bytes — e.g. a fixture produced by an older/buggy sanitizer or hand-edited audit JSON.

Common situations: Hand-editing sanitized fixture identities; a sanitizer change altering the replacement format; a corrupted fixture cache; using a fixture recorded against a different identity policy version.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13). Data as JSON: /api/errors/c99dcbced62dc0f4. Report an issue: GitHub.

Appendix: source

Thrown at crates/openlogi-cli/src/cmd/fixture/record_case/replay.rs:117

            receiver_slots,
        }],
        channels: vec![ReplayChannel {
            id: cassette.channel.clone(),
            connection: ChannelConnection::Connected,
            report_support: cassette.report_support,
        }],
    }
}

fn derive_replay_route(
    selected_route: &DeviceRoute,
    audit: &HidCassetteAudit,
) -> Result<DeviceRoute> {
    match selected_route {
        DeviceRoute::Bolt { slot, .. } => {
            let value = unique_replacement(audit, SanitizedIdentityKind::ReceiverUniqueId)?;
            if value.len() != 16 || !value.is_ascii() {
                bail!("sanitized Bolt receiver identity is not 16-byte ASCII");
            }
            let receiver_uid = std::str::from_utf8(value)
                .map_err(|_| anyhow::anyhow!("sanitized Bolt receiver identity is not ASCII"))?
                .to_string();
            Ok(DeviceRoute::Bolt {
                receiver_uid,
                slot: *slot,
            })
        }
        DeviceRoute::Unifying { slot, .. } => {
            let value = unique_replacement(audit, SanitizedIdentityKind::ReceiverSerialNumber)?;
            if value.len() != 4 {
                bail!("sanitized Unifying receiver identity is not four bytes");
            }
            Ok(DeviceRoute::Unifying {
                receiver_uid: uppercase_hex(value),
                slot: *slot,
            })

View on GitHub (pinned to e846e6f4b4)