{"record":{"id":"92eb2134049e8933","repo":"AprilNEA/OpenLogi","slug":"fixture-structure-verification-failed-asset-must-be-a-non","errorCode":null,"errorMessage":"fixture structure verification failed: {asset} must be a non-symlink directory","messagePattern":"fixture structure verification failed: (.+?) must be a non-symlink directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/openlogi-cli/src/cmd/fixture/verify.rs","lineNumber":222,"sourceCode":"                \"fixture structure verification failed: could not read {asset} {}\",\n                directory.display()\n            )\n        })?\n        .collect::<std::io::Result<Vec<_>>>()\n        .with_context(|| format!(\"fixture structure verification failed while reading {asset}\"))?;\n    entries.sort_by_key(DirEntry::file_name);\n    Ok(entries)\n}\n\nfn require_directory(path: &Path, asset: &str) -> Result<()> {\n    let metadata = fs::symlink_metadata(path).with_context(|| {\n        format!(\n            \"fixture structure verification failed: could not inspect {asset} {}\",\n            path.display()\n        )\n    })?;\n    if metadata.file_type().is_symlink() || !metadata.is_dir() {\n        bail!(\"fixture structure verification failed: {asset} must be a non-symlink directory\");\n    }\n    Ok(())\n}\n\nfn require_entry_directory(entry: &DirEntry, asset: &str) -> Result<()> {\n    let metadata = entry_metadata(entry, asset)?;\n    if metadata.file_type().is_symlink() || !metadata.is_dir() {\n        bail!(\"fixture structure verification failed: {asset} must be a non-symlink directory\");\n    }\n    Ok(())\n}\n\nfn require_regular_file(entry: &DirEntry, asset: &str) -> Result<()> {\n    let metadata = entry_metadata(entry, asset)?;\n    if metadata.file_type().is_symlink() || !metadata.is_file() {\n        bail!(\"fixture structure verification failed: {asset} must be a non-symlink regular file\");\n    }\n    Ok(())","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/AprilNEA/OpenLogi/blob/e846e6f4b4405e33bd6a9aaf949a482ce34cb6d8/crates/openlogi-cli/src/cmd/fixture/verify.rs#L204-L240","documentation":"`require_directory` checks that a required fixture asset path exists as a real directory (via `symlink_metadata`, so a symlink to a directory still fails). Fixtures must be plain directories — symlinks are rejected so the verified corpus is exactly what ships and cannot point outside the tree.","triggerScenarios":"`inspect` calls `require_directory` on a fixture path that is a symlink, or a regular file, or otherwise not a plain directory.","commonSituations":"A developer symlinked a fixture directory into the corpus from elsewhere (dotfiles-style setup, shared fixtures); the path was accidentally replaced by a file; an incomplete copy left the wrong entry type.","solutions":["Replace the symlink with a real directory containing the fixture content (copy the target's contents in).","If the path should be a file, fix the layout so fixtures live in genuine directories.","Re-create the fixture via the authoring tooling instead of linking to an external location.","Re-run `openlogi fixture verify`."],"exampleFix":"# before: fixtures/bolt -> ~/my-fixtures/bolt (symlink)\n# after\nrm fixtures/bolt\ncp -r ~/my-fixtures/bolt fixtures/bolt","handlingStrategy":"validation","validationCode":"let md = std::fs::symlink_metadata(path)?;\nassert!(md.is_dir() && !md.file_type().is_symlink(), \"fixture must be a real directory: {}\", path.display());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never symlink fixture directories into the corpus; copy content instead","Check `ls -la` in the fixtures root after copying or sharing fixtures","Document that the verified corpus must be self-contained"],"tags":["fixture","filesystem","structure","symlink"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"e846e6f4b4405e33bd6a9aaf949a482ce34cb6d8","analyzedAt":"2026-09-13T03:07:16.451Z","contentChangedAt":"2026-09-13T03:07:16.451Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}