Hmbown/CodeWhale · error

failed to enter ACP session cwd {}: {err}

Error message

failed to enter ACP session cwd {}: {err}

What it means

When an ACP session is created, the server temporarily chdir()s into the client-provided cwd via ScopedCurrentDir. std::env::set_current_dir failed for that path; the message names the path and the OS reason (No such file or directory, Permission denied, Not a directory). The process working directory is left unchanged (the guard restores the prior dir on drop).

Source

Thrown at crates/tui/src/acp_server.rs:2082

            "sessionId": session_id,
            "update": update
        }
    });
    write_json_line(writer, notification).await
}

struct ScopedCurrentDir {
    prior: PathBuf,
}

impl ScopedCurrentDir {
    fn new(cwd: &PathBuf) -> Result<Self> {
        let prior = std::env::current_dir()?;
        if cwd.as_os_str().is_empty() {
            return Ok(Self { prior });
        }
        std::env::set_current_dir(cwd)
            .map_err(|err| anyhow!("failed to enter ACP session cwd {}: {err}", cwd.display()))?;
        Ok(Self { prior })
    }
}

impl Drop for ScopedCurrentDir {
    fn drop(&mut self) {
        let _ = std::env::set_current_dir(&self.prior);
    }
}

impl AcpError {
    fn invalid_params(message: impl Into<String>) -> Self {
        Self {
            code: -32602,
            message: message.into(),
        }
    }

View on GitHub (pinned to 8880682c63)

Solutions

  1. Check the cwd exists and is a directory before sending session/new (fs::metadata / Path::is_dir)
  2. Recreate or re-open the workspace folder, then retry the session
  3. Fix mount state or permissions for the path
  4. Send an empty cwd to run in the server's current directory instead

Example fix

// before
let cwd = std::path::PathBuf::from(request.cwd.clone());
let guard = ScopedCurrentDir::new(&cwd)?;
// after
let cwd = std::path::PathBuf::from(request.cwd.clone());
if !cwd.as_os_str().is_empty() && !cwd.is_dir() {
    anyhow::bail!("session cwd does not exist or is not a directory: {}", cwd.display());
}
let guard = ScopedCurrentDir::new(&cwd)?;
Defensive patterns

Strategy: validation

Validate before calling

let cwd = std::path::PathBuf::from(session_cwd.clone());
if !cwd.as_os_str().is_empty() {
    let meta = std::fs::metadata(&cwd)
        .map_err(|err| anyhow::anyhow!("session cwd {} unreadable: {err}", cwd.display()))?;
    if !meta.is_dir() {
        anyhow::bail!("session cwd is not a directory: {}", cwd.display());
    }
}

Type guard

fn is_usable_session_cwd(cwd: &std::path::Path) -> bool {
    cwd.as_os_str().is_empty() || cwd.is_dir()
}

Try / catch

match ScopedCurrentDir::new(&cwd) {
    Ok(guard) => { /* session body */ }
    Err(err) if err.to_string().starts_with("failed to enter ACP session cwd") => {
        return AcpError::invalid_params(format!("cwd unusable: {}", cwd.display()));
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: session/new with a cwd that was deleted after the client opened it, a path on an unmounted network/remote drive, a path that names a file rather than a directory, or missing execute/search permission on a path component. An empty cwd is accepted and means 'stay in the current directory'.

Common situations: Editor workspace deleted or moved while the session starts; WSL/SSHFS/network mounts not yet attached; sandboxed runners without traversal permission; clients forwarding stale workspace paths from restored state.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/7f01f0ed8fe43a54. Report an issue: GitHub.