{"record":{"id":"7f01f0ed8fe43a54","repo":"Hmbown/CodeWhale","slug":"failed-to-enter-acp-session-cwd-err","errorCode":null,"errorMessage":"failed to enter ACP session cwd {}: {err}","messagePattern":"failed to enter ACP session cwd (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/acp_server.rs","lineNumber":2082,"sourceCode":"            \"sessionId\": session_id,\n            \"update\": update\n        }\n    });\n    write_json_line(writer, notification).await\n}\n\nstruct ScopedCurrentDir {\n    prior: PathBuf,\n}\n\nimpl ScopedCurrentDir {\n    fn new(cwd: &PathBuf) -> Result<Self> {\n        let prior = std::env::current_dir()?;\n        if cwd.as_os_str().is_empty() {\n            return Ok(Self { prior });\n        }\n        std::env::set_current_dir(cwd)\n            .map_err(|err| anyhow!(\"failed to enter ACP session cwd {}: {err}\", cwd.display()))?;\n        Ok(Self { prior })\n    }\n}\n\nimpl Drop for ScopedCurrentDir {\n    fn drop(&mut self) {\n        let _ = std::env::set_current_dir(&self.prior);\n    }\n}\n\nimpl AcpError {\n    fn invalid_params(message: impl Into<String>) -> Self {\n        Self {\n            code: -32602,\n            message: message.into(),\n        }\n    }\n","sourceCodeStart":2064,"sourceCodeEnd":2100,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/acp_server.rs#L2064-L2100","documentation":"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).","triggerScenarios":"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'.","commonSituations":"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.","solutions":["Check the cwd exists and is a directory before sending session/new (fs::metadata / Path::is_dir)","Recreate or re-open the workspace folder, then retry the session","Fix mount state or permissions for the path","Send an empty cwd to run in the server's current directory instead"],"exampleFix":"// before\nlet cwd = std::path::PathBuf::from(request.cwd.clone());\nlet guard = ScopedCurrentDir::new(&cwd)?;\n// after\nlet cwd = std::path::PathBuf::from(request.cwd.clone());\nif !cwd.as_os_str().is_empty() && !cwd.is_dir() {\n    anyhow::bail!(\"session cwd does not exist or is not a directory: {}\", cwd.display());\n}\nlet guard = ScopedCurrentDir::new(&cwd)?;","handlingStrategy":"validation","validationCode":"let cwd = std::path::PathBuf::from(session_cwd.clone());\nif !cwd.as_os_str().is_empty() {\n    let meta = std::fs::metadata(&cwd)\n        .map_err(|err| anyhow::anyhow!(\"session cwd {} unreadable: {err}\", cwd.display()))?;\n    if !meta.is_dir() {\n        anyhow::bail!(\"session cwd is not a directory: {}\", cwd.display());\n    }\n}","typeGuard":"fn is_usable_session_cwd(cwd: &std::path::Path) -> bool {\n    cwd.as_os_str().is_empty() || cwd.is_dir()\n}","tryCatchPattern":"match ScopedCurrentDir::new(&cwd) {\n    Ok(guard) => { /* session body */ }\n    Err(err) if err.to_string().starts_with(\"failed to enter ACP session cwd\") => {\n        return AcpError::invalid_params(format!(\"cwd unusable: {}\", cwd.display()));\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Verify the workspace folder still exists right before session/new; editors can hold stale paths after the folder is deleted or moved","Ensure network/remote mounts are attached before starting a session that uses them","Send an empty cwd when the server's current directory is acceptable","Reject file paths and unreadable directories early with invalid_params instead of letting chdir fail"],"tags":["acp","filesystem","session","cwd","permissions"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}