{"record":{"id":"a6c0f08ab928514f","repo":"BigPizzaV3/CodexPlusPlus","slug":"codex-cli-executable-codex-cli-macos-applications-chatgpt","errorCode":null,"errorMessage":"Codex CLI 路径不存在：{executable}\n请填 Codex CLI 可执行文件的完整路径。macOS 桌面版通常在 /Applications/ChatGPT.app/Contents/Resources/codex；npm 全局安装可用 `which codex` / `where codex` 查看。","messagePattern":"Codex CLI 路径不存在：(.+?)\n请填 Codex CLI 可执行文件的完整路径。macOS 桌面版通常在 /Applications/ChatGPT\\.app/Contents/Resources/codex；npm 全局安装可用 `which codex` / `where codex` 查看。","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/connect/app_server.rs","lineNumber":70,"sourceCode":"}\n\n/// 启动前先把「路径本身就不对」的情况挑出来。\n///\n/// 之前不管什么原因失败，用户只会看到一句「请检查 Codex CLI 路径」——填的是目录、\n/// 文件不存在、没有执行权限、甚至 app-server 协议不兼容，全都是这一句，\n/// 于是 #1879 下面积了十几条「到底该填什么路径」。\n///\n/// 裸命令名（codex）交给 PATH 解析，这里只校验看起来像路径的输入。\nfn validate_codex_executable(executable: &str) -> anyhow::Result<()> {\n    let looks_like_path = executable.contains('/')\n        || executable.contains('\\\\')\n        || Path::new(executable).is_absolute();\n    if !looks_like_path {\n        return Ok(());\n    }\n    let path = Path::new(executable);\n    if !path.exists() {\n        bail!(\n            \"Codex CLI 路径不存在：{executable}\\n请填 Codex CLI 可执行文件的完整路径。\\\n             macOS 桌面版通常在 /Applications/ChatGPT.app/Contents/Resources/codex；\\\n             npm 全局安装可用 `which codex` / `where codex` 查看。\"\n        );\n    }\n    if path.is_dir() {\n        bail!(\n            \"Codex CLI 路径指向的是目录而不是可执行文件：{executable}\\n\\\n             请去掉结尾的路径分隔符，或补上具体的可执行文件名。\"\n        );\n    }\n    #[cfg(unix)]\n    {\n        use std::os::unix::fs::PermissionsExt;\n        if let Ok(metadata) = std::fs::metadata(path)\n            && metadata.permissions().mode() & 0o111 == 0\n        {\n            bail!(\"Codex CLI 没有执行权限：{executable}\");","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/connect/app_server.rs#L52-L88","documentation":"validate_codex_executable pre-flights the configured Codex CLI location before spawning the app-server. When the configured executable string looks like a path (contains / or \\ or is absolute) but no file exists at that location, the library throws this error with platform-specific hints. It exists so users see a precise, actionable message instead of a generic spawn failure.","triggerScenarios":"Passing AppServerConfig with an executable field containing a path separator whose file does not exist on disk, then calling CodexAppServer::start. Bare command names like \"codex\" skip this check (resolved via PATH) and fail later in spawn if missing.","commonSituations":"Typed a macOS desktop path (/Applications/ChatGPT.app/Contents/Resources/codex) on Linux, app moved or updated between versions, npm global install location changed after node version switch, typo in the path, trailing filename wrong (codex.exe vs codex).","solutions":["Verify the path with `ls <path>` and correct it to the real binary location","Find the binary: `which codex` (macOS/Linux) or `where codex` (Windows) for npm installs; macOS desktop app bundles it at /Applications/ChatGPT.app/Contents/Resources/codex","If you meant to use PATH lookup, clear the field or set it to just `codex` (no separators)"],"exampleFix":"// before\nAppServerConfig { executable: \"/usr/local/bin/codex-cli\".into(), .. }\n// after\nAppServerConfig { executable: \"codex\".into(), .. } // resolved via PATH, verified with `which codex`","handlingStrategy":"validation","validationCode":"use std::path::Path;\nfn executable_path_ok(executable: &str) -> bool {\n    let looks_like_path = executable.contains('/') || executable.contains('\\\\') || Path::new(executable).is_absolute();\n    !looks_like_path || Path::new(executable).exists()\n}","typeGuard":null,"tryCatchPattern":"match CodexAppServer::start(config).await {\n    Err(e) if e.to_string().contains(\"路径不存在\") => {\n        eprintln!(\"Fix the executable path; run `which codex` or use the macOS app bundle path\");\n        // surface a settings UI instead of retrying\n    }\n    r => r?,\n}","preventionTips":["Store the result of `which codex` / `where codex` in config rather than hand-typing paths","After Codex app updates or node version switches, re-verify the path","Prefer bare `codex` (PATH lookup) when the binary is on PATH","Add a settings pre-check that lstat's the path before saving it"],"tags":["filesystem","configuration","validation","cli"],"backgroundTag":"file-not-found","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}