AprilNEA/OpenLogi · error

could not derive synthetic Unifying serial

Error message

could not derive synthetic Unifying serial

What it means

Thrown by `identity_plan` while building the sanitized identity plan for a receiver-routed fixture: `generate_synthetic_identity(SyntheticIdentityKind::UnifyingReceiverSerial, ordinal).as_bytes()` returned `None`, so no synthetic serial bytes could be derived for the receiver serial number. The generator is expected to produce bytes for every kind/ordinal, so this signals that the synthetic-identity policy refused or cannot encode this input — an internal invariant rather than user error.

Solutions

  1. Check the ordinal passed into `identity_plan` is within the range `openlogi-fixture`'s synthetic identity policy supports, and use a valid one.
  2. Verify `openlogi-cli` and `openlogi-fixture` versions are from the same workspace/build — regenerate with a consistent build.
  3. Inspect `generate_synthetic_identity` for `UnifyingReceiverSerial`: if `as_bytes()` is None by design for some inputs, fix the caller's input or extend the policy.
  4. If reproducible with a stock ordinal, file/fix it as a bug — this path should be unreachable for valid inputs.

Example fix

// before: as_bytes() can be None, error surfaces here
let serial = generate_synthetic_identity(SyntheticIdentityKind::UnifyingReceiverSerial, ordinal)
    .as_bytes()
    .ok_or_else(|| anyhow!("could not derive synthetic Unifying serial"))?
    .to_vec();
// after: assert the invariant with context for diagnosis
let serial = generate_synthetic_identity(SyntheticIdentityKind::UnifyingReceiverSerial, ordinal)
    .as_bytes()
    .with_context(|| format!("synthetic Unifying serial undefined for ordinal {ordinal}"))?
    .to_vec();
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the ordinal is inside the policy's supported range before deriving
let ordinal = profile_ordinal(profile)?;
assert!(ordinal < openlogi_fixture::MAX_SYNTHETIC_ORDINAL,
    "ordinal {ordinal} exceeds synthetic identity policy range");

Try / catch

match identity_plan(profile, route, ordinal) {
    Err(e) if msg_contains(&e, "could not derive synthetic Unifying serial") => {
        eprintln!("identity policy cannot encode ordinal {ordinal}; \
                   check openlogi-fixture version and ordinal range");
        std::process::exit(1);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running the fixture contribute flow for a `DeviceRoute::Receiver`-style profile where the identity generator returns no byte representation for the given `SyntheticIdentityKind::UnifyingReceiverSerial` and ordinal — e.g. an ordinal outside the range the policy encodes, or a policy/derive mismatch after a fixture-crate change.

Common situations: Contributing fixtures with a hand-edited or out-of-range device ordinal; running a newer CLI against an older `openlogi-fixture` policy (or vice versa) where the serial kind lost its byte encoding; a regression in the synthetic-identity policy.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at crates/openlogi-cli/src/cmd/fixture/contribute.rs:341

) -> Result<HidCassetteIdentityPlan> {
    let mut plan = HidCassetteIdentityPlan::default();
    let model = match selected_route {
        DeviceRoute::Bolt { receiver_uid, slot } => {
            plan.insert(
                SanitizedIdentityKind::ReceiverUniqueId,
                receiver_uid.as_bytes().to_vec(),
            )?;
            selected_model(profile, selected_route, *slot)?
        }
        DeviceRoute::Unifying { receiver_uid, slot } => {
            let ordinal = classify_synthetic_profile_identity(
                SyntheticIdentityKind::UnifyingReceiverRoute,
                receiver_uid,
            )?;
            let serial =
                generate_synthetic_identity(SyntheticIdentityKind::UnifyingReceiverSerial, ordinal)
                    .as_bytes()
                    .ok_or_else(|| anyhow!("could not derive synthetic Unifying serial"))?
                    .to_vec();
            plan.insert(SanitizedIdentityKind::ReceiverSerialNumber, serial)?;
            selected_model(profile, selected_route, *slot)?
        }
        DeviceRoute::Direct { .. } => selected_model(
            profile,
            selected_route,
            openlogi_core::hid::DIRECT_DEVICE_INDEX,
        )?,
        DeviceRoute::RawHid { .. } => {
            bail!("raw-HID devices support profile-only contributions")
        }
    };
    add_model_identities(&mut plan, model)?;
    Ok(plan)
}

fn selected_model<'a>(

View on GitHub (pinned to e846e6f4b4)