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
- Point the cwd at a directory, not a file (`mkdir` one if needed)
- Correct the GROK_CHAT_LOCAL_WORKSPACE_CWD value
- 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
- Tab-complete directories with a trailing slash in scripts
- Never pass file paths (configs, archives) as workspace cwd
- Double-check GROK_CHAT_LOCAL_WORKSPACE_CWD targets a folder
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
- local workspace cwd must exist and be canonicalizable: {}: {
- {LOCAL_WORKSPACE_HOME_DENIED}
- no .git file or directory found at {}
- Not a directory: {path}
- path '{}' is not within git repository '{}'
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/17e13036c6b52d40.
Report an issue: GitHub.