AprilNEA/OpenLogi · error

cassette audit has no sanitized receiver identity

Error message

cassette audit has no sanitized receiver identity

What it means

`unique_replacement` looks up the cassette audit's sanitized replacement of a given identity kind (e.g. `ReceiverUniqueId`) and requires exactly one match. If the audit contains no replacement of that kind, the lookup fails with this error — the replay route cannot be derived without the sanitized receiver identity.

Solutions

  1. Use the correct replay path for the cassette type — a direct-connect cassette derives a direct route, not a receiver route
  2. Re-record the fixture so the audit captures the receiver identity
  3. Restore the missing `ReceiverUniqueId` replacement entry in the audit if it was erroneously removed
  4. Check cassette schema/version compatibility between producer and consumer

Example fix

// before: replaying a direct cassette through the receiver path
let route = derive_replay_route(audit, &DeviceRoute::Direct { .. })?; // wrong path
// after: match route kind to the cassette's actual transport
match audit.transport { Bolt => derive_replay_route(audit, bolt_route), Direct => direct_route }
Defensive patterns

Strategy: validation

Validate before calling

fn has_unique_replacement(audit: &CassetteAudit, kind: SanitizedIdentityKind) -> bool {
    audit.replacements.iter().filter(|r| r.kind == kind).count() == 1
}
// require has_unique_replacement(audit, SanitizedIdentityKind::ReceiverUniqueId) before deriving a receiver route

Try / catch

match unique_replacement(audit, SanitizedIdentityKind::ReceiverUniqueId) {
    Ok(v) => derive_route(v),
    Err(_) => eprintln!("no unique sanitized receiver identity; this cassette is not receiver-derived"),
}

Prevention

When it happens

Trigger: Calling `derive_replay_route` on a cassette whose audit `replacements` list lacks an entry for `ReceiverUniqueId` — the fixture never saw a Bolt/Unifying receiver unique id, or the audit was regenerated/stripped.

Common situations: Replaying a direct-connection (Bluetooth/wired) cassette as if it came through a Bolt receiver; auditing tools that dropped replacements they considered non-sensitive; schema drift between cassette versions.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

        } => Ok(DeviceRoute::Direct {
            vendor_id: *vendor_id,
            product_id: *product_id,
        }),
        DeviceRoute::RawHid { .. } => {
            bail!("raw HID routes are outside HID++ fixture case capture")
        }
    }
}

fn unique_replacement(audit: &HidCassetteAudit, kind: SanitizedIdentityKind) -> Result<&[u8]> {
    let mut replacements = audit
        .replacements
        .iter()
        .filter(|replacement| replacement.kind == kind);
    let value = replacements
        .next()
        .map(|replacement| replacement.synthetic_value.as_slice())
        .ok_or_else(|| anyhow::anyhow!("cassette audit has no sanitized receiver identity"))?;
    if replacements.next().is_some() {
        bail!("cassette audit has multiple sanitized receiver identities");
    }
    Ok(value)
}

#[cfg(test)]
mod tests {
    use openlogi_device::write::FeatureEntry;
    use openlogi_fixture::{
        CassetteExchange, FIXTURE_SCHEMA_VERSION, HidCassette, ReportSupport, RequestMatch,
    };
    use openlogi_hid::FeatureType;
    use openlogi_hid::recording::IdentityReplacement;

    use super::*;

    fn target(route: DeviceRoute, product_id: u16) -> TargetCandidate {

View on GitHub (pinned to e846e6f4b4)