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

  1. Edit the fixture manifest so the case name contains only safe filename characters (no `/`, `\`, and not `.` or `..`).
  2. 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.
  3. Fix any code that generates case names to sanitize or reject separators at authoring time.
  4. 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

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


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)