zeroclaw-labs/zeroclaw · error · anyhow::Error

grok_cli working_directory must be an absolute path

Error message

grok_cli working_directory must be an absolute path

What it means

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.

Source

Thrown at crates/zeroclaw-providers/src/grok_cli.rs:493

            working_directory: None,
            env_passthrough: Vec::new(),
            extra_args: Vec::new(),
            max_acp_stdout_bytes: None,
            timeout_secs: None,
            vision_enabled: false,
        }
    }

    fn validate_working_directory(value: &str) -> anyhow::Result<PathBuf> {
        let trimmed = value.trim();
        if trimmed.is_empty() {
            anyhow::bail!(
                "grok_cli requires an explicit working_directory for the ACP session boundary"
            );
        }
        let path = Path::new(trimmed);
        if !path.is_absolute() {
            anyhow::bail!("grok_cli working_directory must be an absolute path");
        }
        let canonical = std::fs::canonicalize(path).map_err(|_| {
            anyhow::Error::msg("grok_cli working_directory does not exist or is inaccessible")
        })?;
        if !canonical.is_dir() {
            anyhow::bail!("grok_cli working_directory must identify a directory");
        }
        Ok(canonical)
    }

    fn validate_acp_stdout_limit(value: Option<usize>) -> anyhow::Result<usize> {
        let limit = value.unwrap_or(acp::DEFAULT_ACP_STDOUT_LIMIT_BYTES);
        if !(acp::MIN_ACP_STDOUT_LIMIT_BYTES..=acp::MAX_ACP_STDOUT_LIMIT_BYTES).contains(&limit) {
            anyhow::bail!(
                "grok_cli max_acp_stdout_bytes must be between {} and {} bytes",
                acp::MIN_ACP_STDOUT_LIMIT_BYTES,
                acp::MAX_ACP_STDOUT_LIMIT_BYTES
            );

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Use an absolute path such as /home/user/project
  2. Expand ~ programmatically (dirs/shellexpand) before configuring
  3. Emit the canonicalized path in logs to catch drift

Example fix

# before
working_directory = "~/myproject"

# after
working_directory = "/home/beagle/myproject"
Defensive patterns

Strategy: validation

Validate before calling

fn working_directory_absolute(v: &str) -> bool {
    std::path::Path::new(v.trim()).is_absolute()
}

Type guard

fn working_directory_absolute(v: &str) -> bool {
    std::path::Path::new(v.trim()).is_absolute()
}

Prevention

When it happens

Trigger: Passing './myproject', 'src/', or '~/work' as working_directory; configs written for one machine's cwd reused on another.

Common situations: 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.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/ebf22f6c20f83b26. Report an issue: GitHub.