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

grok_cli working_directory must identify a directory

Error message

grok_cli working_directory must identify a directory

What it means

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.

Source

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

        }
    }

    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
            );
        }
        Ok(limit)
    }

    fn normalize_and_validate_env_passthrough(names: Vec<String>) -> anyhow::Result<Vec<String>> {
        let mut normalized: Vec<String> = Vec::with_capacity(names.len());

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Point at the directory containing the file instead
  2. Recreate or repair the expected directory
  3. After deploy scripts that move paths, re-validate config

Example fix

# before
working_directory = "/home/user/project/README.md"

# after
working_directory = "/home/user/project"
Defensive patterns

Strategy: validation

Validate before calling

fn working_directory_usable(v: &str) -> bool {
    std::fs::canonicalize(v.trim()).map(|p| p.is_dir()).unwrap_or(false)
}

Type guard

fn working_directory_usable(v: &str) -> bool {
    std::fs::canonicalize(v.trim()).map(|p| p.is_dir()).unwrap_or(false)
}

Prevention

When it happens

Trigger: 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.

Common situations: Copy-pasting a file path into the config; symlink swap during deployments; tempdirs recreated as files by other tooling.

Related errors


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