AprilNEA/OpenLogi · error
relationship verification failed: fixture case name
Error message
relationship verification failed: fixture case name {case_name:?} is not a safe file name What it means
`case_file_name` refuses to turn a fixture case name into a filename when the name would be dangerous as a path component: exactly `.` or `..`, or containing `/` or `\`. This is a path-traversal guard ensuring manifest case names map to safe files inside the fixture directory.
Solutions
- Edit the fixture manifest so the case name contains only safe filename characters (no `/`, `\`, and not `.` or `..`).
- If the case genuinely needs hierarchy, model it as a separate fixture directory whose name equals the manifest id, not as a slashed case name.
- Fix any code that generates case names to sanitize or reject separators at authoring time.
- Re-run `openlogi fixture verify`.
Example fix
// before [fixtures.cases] "sensor/report" = true // after [fixtures.cases] "sensor-report" = true
Defensive patterns
Strategy: validation
Validate before calling
fn is_safe_case_name(name: &str) -> bool {
!matches!(name, "." | "..") && !name.contains('/') && !name.contains('\\') && !name.is_empty()
}
assert!(is_safe_case_name(&case_name)); Type guard
fn is_safe_case_name(name: &str) -> bool {
!matches!(name, "." | "..") && !name.contains('/') && !name.contains('\\')
} Prevention
- Validate case names at manifest-authoring time, not only at verification time
- Reject or sanitize user/generated names containing path separators
- Keep case names to kebab-case to make unsafe names obvious
When it happens
Trigger: `load_cassettes` calls `case_file_name` with a manifest case name that is `.`/`..` or contains a slash or backslash; the error then aborts fixture verification.
Common situations: A hand-edited manifest accidentally embeds a path or separator in a case name (e.g. `sub/case`); an auto-generated case name concatenates strings with `/`; a copy-paste introduced `..` or a Windows separator.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- --name must not be empty
- --channel must not be empty
- no sanitized channel candidate reproduced the captured…
- sanitized channel candidates reproduced the capture; target…
- sanitized Bolt receiver identity is not 16-byte ASCII
AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13).
Data as JSON: /api/errors/efc520ff18c23b42.
Report an issue: GitHub.
Appendix: source
Thrown at crates/openlogi-cli/src/cmd/fixture/verify.rs:172
let cassette: HidCassette = read_json(&entry.path(), "HID cassette")?;
if cassette.name != *case_name {
bail!(
"relationship verification failed: cassette file {file_name:?} contains case {:?}",
cassette.name
);
}
found.insert(file_name, cassette);
}
if let Some(missing) = expected.keys().find(|name| !found.contains_key(*name)) {
bail!("relationship verification failed: missing declared fixture case file {missing:?}");
}
Ok(found.into_values().collect())
}
fn case_file_name(case_name: &str) -> Result<String> {
if matches!(case_name, "." | "..") || case_name.contains('/') || case_name.contains('\\') {
bail!(
"relationship verification failed: fixture case name {case_name:?} is not a safe file name"
);
}
Ok(format!("{case_name}.json"))
}
fn require_directory_id(directory: &Path, fixture_id: &str) -> Result<()> {
if directory.file_name().and_then(|name| name.to_str()) == Some(fixture_id) {
Ok(())
} else {
bail!(
"relationship verification failed: fixture directory name must equal manifest id {fixture_id:?}"
)
}
}
fn read_json<T: DeserializeOwned>(path: &Path, asset: &str) -> Result<T> {
let bytes = fs::read(path).with_context(|| {View on GitHub (pinned to e846e6f4b4)