{"record":{"id":"1f6fdd5482f3c3b7","repo":"zeroclaw-labs/zeroclaw","slug":"grok-cli-working-directory-must-identify-a-directo","errorCode":null,"errorMessage":"grok_cli working_directory must identify a directory","messagePattern":"grok_cli working_directory must identify a directory","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/grok_cli.rs","lineNumber":499,"sourceCode":"        }\n    }\n\n    fn validate_working_directory(value: &str) -> anyhow::Result<PathBuf> {\n        let trimmed = value.trim();\n        if trimmed.is_empty() {\n            anyhow::bail!(\n                \"grok_cli requires an explicit working_directory for the ACP session boundary\"\n            );\n        }\n        let path = Path::new(trimmed);\n        if !path.is_absolute() {\n            anyhow::bail!(\"grok_cli working_directory must be an absolute path\");\n        }\n        let canonical = std::fs::canonicalize(path).map_err(|_| {\n            anyhow::Error::msg(\"grok_cli working_directory does not exist or is inaccessible\")\n        })?;\n        if !canonical.is_dir() {\n            anyhow::bail!(\"grok_cli working_directory must identify a directory\");\n        }\n        Ok(canonical)\n    }\n\n    fn validate_acp_stdout_limit(value: Option<usize>) -> anyhow::Result<usize> {\n        let limit = value.unwrap_or(acp::DEFAULT_ACP_STDOUT_LIMIT_BYTES);\n        if !(acp::MIN_ACP_STDOUT_LIMIT_BYTES..=acp::MAX_ACP_STDOUT_LIMIT_BYTES).contains(&limit) {\n            anyhow::bail!(\n                \"grok_cli max_acp_stdout_bytes must be between {} and {} bytes\",\n                acp::MIN_ACP_STDOUT_LIMIT_BYTES,\n                acp::MAX_ACP_STDOUT_LIMIT_BYTES\n            );\n        }\n        Ok(limit)\n    }\n\n    fn normalize_and_validate_env_passthrough(names: Vec<String>) -> anyhow::Result<Vec<String>> {\n        let mut normalized: Vec<String> = Vec::with_capacity(names.len());","sourceCodeStart":481,"sourceCodeEnd":517,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/grok_cli.rs#L481-L517","documentation":"The working_directory value resolved (std::fs::canonicalize succeeded, so it exists and is accessible) but does not identify a directory - is_dir() returned false. The ACP session boundary must be a directory, not a file, socket, or symlink-to-file.","triggerScenarios":"Pointing working_directory at a regular file, a socket/fifo, or a symlink whose target is a file; a path that was a directory when configured and has since been replaced by a file.","commonSituations":"Copy-pasting a file path into the config; symlink swap during deployments; tempdirs recreated as files by other tooling.","solutions":["Point at the directory containing the file instead","Recreate or repair the expected directory","After deploy scripts that move paths, re-validate config"],"exampleFix":"# before\nworking_directory = \"/home/user/project/README.md\"\n\n# after\nworking_directory = \"/home/user/project\"","handlingStrategy":"validation","validationCode":"fn working_directory_usable(v: &str) -> bool {\n    std::fs::canonicalize(v.trim()).map(|p| p.is_dir()).unwrap_or(false)\n}","typeGuard":"fn working_directory_usable(v: &str) -> bool {\n    std::fs::canonicalize(v.trim()).map(|p| p.is_dir()).unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Verify the path is a directory in deploy preflight checks","Beware symlink swaps during deployments; canonicalize resolves them","Fail config load when working_directory is not a directory"],"tags":["rust","zeroclaw","grok-cli","path","filesystem","configuration"],"backgroundTag":"path-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}