AprilNEA/OpenLogi · error
output must not be a symlink
Error message
{asset} output must not be a symlink What it means
`reject_symlink` ensures an output path that is about to be published is not a symlink; unlike the require_* helpers it tolerates a nonexistent path (NotFound is OK, since publishing will create it) but bails if the path already exists as a symlink, and wraps other inspection errors with `could not inspect {asset} output`.
Solutions
- Remove the symlink at the output path (`rm <path>`) and re-run finish so a real file is written.
- If the link was intentional (e.g. sync tooling), move the actual data to the output location and delete the link first.
- Inspect with `ls -la <path>` to confirm what exists before re-running.
Example fix
// before (state.json -> ~/sync/state.json) // after rm out/mx-master/state.json && openlogi fixture contribute finish --id mx-master --name "MX Master" ...
Defensive patterns
Strategy: validation
Validate before calling
[ ! -L "$OUT_PATH" ] || { echo "$OUT_PATH must not be a symlink" >&2; exit 1; } Prevention
- Keep output locations free of links from sync/backup tooling.
- Remove any stale symlink at the output path before finishing a contribution.
- Write outputs inside the fixture directory itself, which the tooling controls.
When it happens
Trigger: publish_manifest_and_finish finds an existing symlink at an output location (manifest or state output) while finalizing the contribution. Also fires on any non-NotFound I/O error while inspecting the path.
Common situations: A previous tool or setup linked the output file to elsewhere (e.g. symlinked state.json into a synced folder); leftover links from an older workflow.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- must be a non-symlink directory
- must be a non-symlink regular file
- output already exists; pass --force to replace it after…
- fixture structure verification failed
- fixture structure verification failed
AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13).
Data as JSON: /api/errors/9de9e88719f8f738.
Report an issue: GitHub.
Appendix: source
Thrown at crates/openlogi-cli/src/cmd/fixture/contribute.rs:503
if metadata.file_type().is_symlink() || !metadata.is_dir() {
bail!("{asset} must be a non-symlink directory");
}
Ok(())
}
fn require_regular_file(path: &Path, asset: &str) -> Result<()> {
let metadata =
fs::symlink_metadata(path).with_context(|| format!("could not inspect {asset}"))?;
if metadata.file_type().is_symlink() || !metadata.is_file() {
bail!("{asset} must be a non-symlink regular file");
}
Ok(())
}
fn reject_symlink(path: &Path, asset: &str) -> Result<()> {
match fs::symlink_metadata(path) {
Ok(metadata) if metadata.file_type().is_symlink() => {
bail!("{asset} output must not be a symlink")
}
Ok(_) => Ok(()),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
Err(error) => Err(error).with_context(|| format!("could not inspect {asset} output")),
}
}
#[cfg(test)]
mod tests {
use openlogi_fixture::CANONICAL_DEVICE_PROFILE_JSON;
use super::*;
#[test]
fn output_directory_must_match_the_synthetic_id() {
let args = ContributeArgs {
id: "fixture-001".to_string(),
name: "Synthetic mouse".to_string(),View on GitHub (pinned to e846e6f4b4)