{"record":{"id":"ebf22f6c20f83b26","repo":"zeroclaw-labs/zeroclaw","slug":"grok-cli-working-directory-must-be-an-absolute-pat","errorCode":null,"errorMessage":"grok_cli working_directory must be an absolute path","messagePattern":"grok_cli working_directory must be an absolute path","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/grok_cli.rs","lineNumber":493,"sourceCode":"            working_directory: None,\n            env_passthrough: Vec::new(),\n            extra_args: Vec::new(),\n            max_acp_stdout_bytes: None,\n            timeout_secs: None,\n            vision_enabled: false,\n        }\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            );","sourceCodeStart":475,"sourceCodeEnd":511,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/grok_cli.rs#L475-L511","documentation":"validate_working_directory rejects relative paths: the ACP child's cwd must be pinned independently of where ZeroClaw was launched, so Path::is_absolute() gates the value before canonicalization. Note that '~' is not expanded - it is a relative path here.","triggerScenarios":"Passing './myproject', 'src/', or '~/work' as working_directory; configs written for one machine's cwd reused on another.","commonSituations":"Tilde in config assumed to expand; daemon started from a different directory than the config author tested; relative paths that only work in interactive shells.","solutions":["Use an absolute path such as /home/user/project","Expand ~ programmatically (dirs/shellexpand) before configuring","Emit the canonicalized path in logs to catch drift"],"exampleFix":"# before\nworking_directory = \"~/myproject\"\n\n# after\nworking_directory = \"/home/beagle/myproject\"","handlingStrategy":"validation","validationCode":"fn working_directory_absolute(v: &str) -> bool {\n    std::path::Path::new(v.trim()).is_absolute()\n}","typeGuard":"fn working_directory_absolute(v: &str) -> bool {\n    std::path::Path::new(v.trim()).is_absolute()\n}","tryCatchPattern":null,"preventionTips":["Expand ~ and env vars before writing the config value","Use dirs::home_dir() to build paths programmatically","Reject relative paths in config linting"],"tags":["rust","zeroclaw","grok-cli","path","absolute-path","configuration"],"backgroundTag":"path-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}