xai-org/grok-build · error

local workspace cwd must be an existing directory: {}

Error message

local workspace cwd must be an existing directory: {}

What it means

After canonicalization, `validate_local_workspace_cwd` requires the path to be an existing directory. If the canonical path is not a directory (e.g. it is a file, socket, or fifo), it bails with `local workspace cwd must be an existing directory: <path>` (session_startup.rs:508-511).

Source

Thrown at crates/codegen/xai-grok-pager/src/app/session_startup.rs:517

            .join(path)
    };
    let canon = abs.canonicalize().map_err(|e| {
        anyhow::anyhow!(
            "local workspace cwd must exist and be canonicalizable: {}: {e}",
            abs.display()
        )
    })?;
    if !canon.is_dir() {
        anyhow::bail!(
            "local workspace cwd must be an existing directory: {}",
            canon.display()
        );
    }
    if env_truthy(GROK_CHAT_LOCAL_WORKSPACE_ALLOW_HOME_ENV) {
        return Ok(canon);
    }
    if canon == std::path::Path::new("/") {
        anyhow::bail!("{LOCAL_WORKSPACE_HOME_DENIED}");
    }
    if let Some(home_path) = xai_dirs::home_dir() {
        let home_canon = home_path.canonicalize().unwrap_or(home_path);
        if canon == home_canon {
            anyhow::bail!("{LOCAL_WORKSPACE_HOME_DENIED}");
        }
    }
    Ok(canon)
}
/// Banner and first-run confirm for the local-workspace own and attach modes.
///
/// Skip confirm only with `GROK_CHAT_LOCAL_WORKSPACE_ACK=1` or a prior ack file.
/// Non-TTY without ACK refuses (fail closed).
#[cfg(feature = "local-workspace")]
pub fn emit_local_workspace_startup_ux(cfg: &LocalWorkspaceConfig) -> anyhow::Result<()> {
    use std::io::IsTerminal;
    emit_local_workspace_startup_ux_with(cfg, std::io::stdin().is_terminal())
}

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Point the cwd at a directory, not a file (`mkdir` one if needed)
  2. Correct the GROK_CHAT_LOCAL_WORKSPACE_CWD value
  3. Remove/rename the file if the intended path was supposed to be a directory

Example fix

// before
export GROK_CHAT_LOCAL_WORKSPACE_CWD=/tmp/notes.txt
// after
mkdir -p /tmp/notes
export GROK_CHAT_LOCAL_WORKSPACE_CWD=/tmp/notes
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_is_dir(p: &std::path::Path) -> Result<(), String> {
    if p.is_file() { return Err(format!("{p:?} is a file; pass a directory")); }
    Ok(())
}

Type guard

fn is_existing_dir(p: &std::path::Path) -> bool { p.canonicalize().map(|c| c.is_dir()).unwrap_or(false) }

Try / catch

match validate_local_workspace_cwd(&cwd) {
    Err(e) if e.to_string().contains("existing directory") => {
        eprintln!("point the workspace at a directory, not a file: {e}")
    }
    other => other?,
}

Prevention

When it happens

Trigger: Pointing `--local-workspace` cwd, its CLI argument, or GROK_CHAT_LOCAL_WORKSPACE_CWD at a regular file that exists and canonicalizes fine but is not a directory.

Common situations: Passing a config file or archive path instead of a folder; tab-completion grabbing a file; cwd env var pointing at a file created by a previous tool run.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/17e13036c6b52d40. Report an issue: GitHub.