AprilNEA/OpenLogi · error

sanitized channel candidates reproduced the capture; target…

Error message

{count} sanitized channel candidates reproduced the capture; target channel resolution is ambiguous, so no fixture was written

What it means

`require_single_passing_candidate` requires a unique passing sanitized channel candidate; when more than one candidate reproduces the capture, the target channel is ambiguous and writing a fixture would bake in an arbitrary choice, so the error aborts.

Solutions

  1. Constrain the target with a more specific --channel so only one candidate is considered
  2. Choose an operation/observation that discriminates channels (channel-specific semantics)
  3. If ambiguity is legitimate for this case, adjust the fixture plan/sanitization to pin the expected channel explicitly

Example fix

// before (ambiguous)
openlogi fixture record-case --name battery-query   # matches both channels
// after: pin the channel
openlogi fixture record-case --name battery-query --channel short-hidpp
Defensive patterns

Strategy: validation

Validate before calling

// pin the channel explicitly to avoid ambiguous candidate matching
let args = RecordCaseArgs { channel: "short-hidpp".into(), ..default };
assert!(!args.channel.is_empty());

Try / catch

if err.to_string().contains("resolution is ambiguous") {
    eprintln!("multiple channels match; pass a specific --channel to disambiguate");
}

Prevention

When it happens

Trigger: Recording a case where two or more sanitized channel candidates both pass semantic-observation matching and strict replay — e.g. a request that succeeds identically on both short and long HID++ channels.

Common situations: Recording feature queries that are channel-agnostic so both channel variants replay identically; overly permissive sanitization making candidates indistinguishable; targeting a device where the operation has no channel-specific behavior.

Related errors


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

Appendix: source

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

    let Ok(backend) = ReplayBackend::new(topology, vec![candidate.cassette.clone()]) else {
        return false;
    };
    let replayed = operation.observe(&backend, &route).await;
    replayed.ensure_replayable().is_ok()
        && replayed == *captured
        && backend.require_complete().is_ok()
}

fn require_single_passing_candidate(
    mut candidates: Vec<SanitizedCandidate>,
) -> Result<SanitizedCandidate> {
    match candidates.len() {
        1 => Ok(candidates.remove(0)),
        0 => bail!(
            "no sanitized channel candidate reproduced the captured semantic observation and \
             completed strict replay; no fixture was written"
        ),
        count => bail!(
            "{count} sanitized channel candidates reproduced the capture; target channel \
             resolution is ambiguous, so no fixture was written"
        ),
    }
}

fn replay_topology(
    target: &TargetCandidate,
    route: &DeviceRoute,
    cassette: &HidCassette,
) -> ReplayTopology {
    let receiver_slots = match route {
        DeviceRoute::Bolt { slot, .. } | DeviceRoute::Unifying { slot, .. } => {
            vec![ReceiverSlot {
                slot: *slot,
                state: ReceiverSlotState::Paired(ReceiverLinkState::Online),
            }]
        }

View on GitHub (pinned to e846e6f4b4)