AprilNEA/OpenLogi · error
the selected device has no stable synthetic identity for…
Error message
the selected device has no stable synthetic identity for cassette relationships; rerun with --profile-only
What it means
Cassette files record sanitized identity material (device unit ID and/or serial number) so relationships between cassettes can be verified. `add_model_identities` refuses to proceed when the selected device's `DeviceModelInfo` has an all-zero unit ID and no serial number, because there is no stable identity to anchor cassette relationships; it suggests rerunning with `--profile-only`, which omits cassette capture.
Solutions
- Rerun with `--profile-only` as the error suggests — this is the supported mode when no stable identity exists
- Re-capture the device profile so the unit ID/serial probe runs again and identity fields are populated
- Verify on hardware (`openlogi list` / diagnostics) that the device actually reports a non-zero unit ID or serial; if it never does, the device cannot anchor cassette relationships
- Pick a different device/slot that reports stable identity if multiple devices are available
Example fix
// before: full cassette capture with an identity-less device $ openlogi fixture contribute --id my-fixture --device 1 --output output/my-fixture Error: the selected device has no stable synthetic identity for cassette relationships; rerun with --profile-only // after $ openlogi fixture contribute --id my-fixture --device 1 --output output/my-fixture --profile-only
Defensive patterns
Strategy: validation
Validate before calling
// Before a full capture, confirm the selected model has stable identity
fn has_stable_identity(model: &DeviceModelInfo) -> bool {
model.unit_id != [0; 4] || model.serial_number.is_some()
}
if !has_stable_identity(&model) {
eprintln!("no stable identity: use --profile-only");
} Type guard
fn is_cassette_capable(model: &DeviceModelInfo) -> bool {
model.unit_id != [0; 4] || model.serial_number.is_some()
} Try / catch
match contribute_result {
Err(e) if e.to_string().contains("no stable synthetic identity") => {
eprintln!("falling back to --profile-only");
// rerun with args.profile_only = true
}
other => other?,
} Prevention
- Inspect the captured profile's model_info for a non-zero unit_id or serial before attempting full capture
- Re-probe the device (re-capture the profile) if identity fields come back zeroed
- Prefer devices that report serial numbers for cassette contributions
- Fall back to `--profile-only` automatically when identity fields are absent
When it happens
Trigger: Running a full `openlogi fixture contribute` capture when the selected device model reports `unit_id == [0;4]` and `serial_number == None` — e.g. a device that failed identity probing, a cloned/anonymous unit, or a profile snapshot taken before the device reported its identity.
Common situations: Devices whose HID++ identity probe returned zeros (firmware quirk or probe failure); fixtures built from stale profiles captured before a firmware update changed identity reporting; contributing from a mock/test device without identity data; selecting a slot whose device lacks model_info identity fields.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- raw-HID devices support profile-only contributions
- the selected direct-capture target does not match the…
- resumable fixture cases contain a non-UTF-8 entry
- resumable fixture cases contain unexpected file
- fixture directory has no UTF-8 synthetic ID
AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13).
Data as JSON: /api/errors/27b6a30051316e7b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/openlogi-cli/src/cmd/fixture/contribute.rs:379
route: &DeviceRoute,
slot: u8,
) -> Result<&'a DeviceModelInfo> {
profile
.inventories
.iter()
.find(|inventory| {
inventory.paired.iter().any(|device| {
DeviceRoute::device_route_for(inventory, device.slot).as_ref() == Some(route)
})
})
.and_then(|inventory| inventory.paired.iter().find(|device| device.slot == slot))
.and_then(|device| device.model_info.as_ref())
.ok_or_else(|| anyhow!("selected profile route has no identity-bearing device model"))
}
fn add_model_identities(plan: &mut HidCassetteIdentityPlan, model: &DeviceModelInfo) -> Result<()> {
if model.unit_id == [0; 4] && model.serial_number.is_none() {
bail!(
"the selected device has no stable synthetic identity for cassette relationships; \
rerun with --profile-only"
);
}
if model.unit_id != [0; 4] {
plan.insert(SanitizedIdentityKind::DeviceUnitId, model.unit_id.to_vec())?;
}
if let Some(serial) = model.serial_number.as_deref() {
plan.insert(
SanitizedIdentityKind::DeviceSerialNumber,
serial.as_bytes().to_vec(),
)?;
}
Ok(())
}
fn require_same_structural_route(expected: &DeviceRoute, actual: &DeviceRoute) -> Result<()> {
let matches = match (expected, actual) {View on GitHub (pinned to e846e6f4b4)