{"record":{"id":"1179708f09f2fd97","repo":"zeroclaw-labs/zeroclaw","slug":"manifest-exec-binary-is-not-a-regular-file","errorCode":null,"errorMessage":"manifest exec binary is not a regular file: {}","messagePattern":"manifest exec binary is not a regular file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-hardware/src/loader.rs","lineNumber":236,"sourceCode":"                    \"binary_path\": raw_binary_path.display().to_string(),\n                    \"error\": format!(\"{}\", e),\n                })),\n            \"cannot canonicalize plugin binary path\"\n        );\n        anyhow::Error::msg(format!(\n            \"cannot canonicalize binary path {}: {e}\",\n            raw_binary_path.display()\n        ))\n    })?;\n    if !binary_path.starts_with(&canonical_plugin_dir) {\n        anyhow::bail!(\n            \"manifest exec binary escapes plugin directory: {} is not under {}\",\n            binary_path.display().to_string(),\n            canonical_plugin_dir.display()\n        );\n    }\n    if !binary_path.is_file() {\n        anyhow::bail!(\n            \"manifest exec binary is not a regular file: {}\",\n            binary_path.display()\n        );\n    }\n\n    let name = manifest.tool.name.clone();\n    let version = manifest.tool.version.clone();\n    let tool: Box<dyn Tool> = Box::new(SubprocessTool::new(manifest, binary_path));\n\n    Ok(LoadedPlugin {\n        name,\n        version,\n        tool,\n    })\n}\n\n/// Return the path `~/.zeroclaw/tools/` using the `directories` crate.\npub fn plugin_tools_dir() -> Result<PathBuf> {","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-hardware/src/loader.rs#L218-L254","documentation":"Final filesystem check on the exec binary in `load_one_plugin`: once existence, canonicalization, and containment pass, the path must be a regular file. Directories, FIFOs, sockets, and device nodes that happen to carry the expected name are rejected — `exists()` alone is intentionally not trusted for something that will be executed.","triggerScenarios":"`binary = \"bin\"` pointing at a directory; a named pipe or device node created where the executable is expected; scaffolding scripts leaving placeholders behind.","commonSituations":"Omitting the file name so the path resolves to a directory; placeholder files created with mkfifo/mknod or by installers; a subdirectory shadowing the binary name.","solutions":["Point `binary` at the executable file itself, including its file name","Replace any directory or FIFO placeholder with the real compiled binary"],"exampleFix":"# before\n[exec]\nbinary = \"bin\"\n# after\n[exec]\nbinary = \"bin/my-tool\"","handlingStrategy":"validation","validationCode":"let binary = plugin_dir.join(&manifest.exec.binary);\nif !binary.is_file() {\n    anyhow::bail!(\"exec binary must be a regular file: {}\", binary.display());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include the executable file name in the binary path, not just its directory","Ship real compiled files; reject placeholder dirs/FIFOs during packaging checks"],"tags":["hardware","plugin","manifest","invalid-file-type","loader"],"backgroundTag":"not-a-regular-file","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}