AprilNEA/OpenLogi · error

sanitized Bolt receiver identity is not ASCII

Error message

sanitized Bolt receiver identity is not ASCII

What it means

`derive_replay_route` rebuilds a `DeviceRoute::Bolt` for replay from the cassette's audit record of sanitized identities. The sanitized receiver unique-id replacement must be exactly 16 bytes of ASCII (it becomes the receiver UID string); if it isn't, replay cannot reconstruct a valid route and this error is thrown (distinct sibling messages cover the non-16-byte vs non-ASCII cases).

Solutions

  1. Re-record the fixture so the sanitizer produces a correct 16-byte ASCII receiver unique-id
  2. Fix the audit `replacements` entry to hold a 16-byte ASCII synthetic value (and keep it consistent with every place it appears)
  3. Check cassette/schema version compatibility between the producing and replaying tool versions
  4. Validate the cassette with the fixture crate's privacy/relationship verification before replay

Example fix

// before (hand-edited audit)
[[replacements]]
kind = "receiver-unique-id"
synthetic_value = "abc"
// after
[[replacements]]
kind = "receiver-unique-id"
synthetic_value = "A1B2C3D4E5F60718"  # 16 ASCII bytes
Defensive patterns

Strategy: validation

Validate before calling

fn replay_route_supported(audit: &CassetteAudit) -> bool {
    audit.replacements.iter()
        .filter(|r| r.kind == SanitizedIdentityKind::ReceiverUniqueId)
        .all(|r| r.synthetic_value.len() == 16 && r.synthetic_value.is_ascii())
}

Type guard

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

Try / catch

match derive_replay_route(audit, route) {
    Ok(r) => replay(r),
    Err(e) if e.to_string().contains("sanitized Bolt receiver identity") =>
        eprintln!("cassette audit identity is malformed; re-record the fixture"),
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Replaying or validating a cassette whose audit lists a `ReceiverUniqueId` sanitized replacement that is not 16-byte ASCII — e.g. a cassette produced by an older sanitizer, hand-edited audit, or corrupted synthetic value.

Common situations: Replaying cassettes generated before the sanitizer enforced the 16-byte ASCII format, fixtures edited by hand for privacy review, or an audit file truncated/corrupted in transit.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

            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,
            })
        }
        DeviceRoute::Direct {
            vendor_id,

View on GitHub (pinned to e846e6f4b4)