{"record":{"id":"c575d9b3e173d45d","repo":"Hmbown/CodeWhale","slug":"failed-to-inherit-reviewed-plugin-executable-descr","errorCode":null,"errorMessage":"failed to inherit reviewed plugin executable descriptor","messagePattern":"failed to inherit reviewed plugin executable descriptor","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp.rs","lineNumber":1041,"sourceCode":"            .iter()\n            .map(|byte| format!(\"{byte:02x}\"))\n            .collect::<String>();\n        if &actual != expected {\n            anyhow::bail!(\"reviewed plugin executable bytes changed before spawn\");\n        }\n        file.seek(std::io::SeekFrom::Start(0))\n            .context(\"rewind reviewed launch file after verification\")?;\n\n        #[cfg(unix)]\n        let launch_path = {\n            use std::os::fd::AsRawFd as _;\n            let fd = file.as_raw_fd();\n            // SAFETY: `fd` is owned by `file`; clearing only FD_CLOEXEC keeps\n            // that same descriptor available across the imminent exec.\n            let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };\n            if flags < 0 || unsafe { libc::fcntl(fd, libc::F_SETFD, flags & !libc::FD_CLOEXEC) } < 0\n            {\n                anyhow::bail!(\"failed to inherit reviewed plugin executable descriptor\");\n            }\n            #[cfg(target_os = \"linux\")]\n            let prefix = \"/proc/self/fd\";\n            #[cfg(not(target_os = \"linux\"))]\n            let prefix = \"/dev/fd\";\n            std::ffi::OsString::from(format!(\"{prefix}/{fd}\"))\n        };\n\n        #[cfg(not(unix))]\n        let launch_path = path.as_os_str().to_os_string();\n\n        self.opened_files.push(file);\n        Ok(launch_path)\n    }\n\n    fn bind_cwd(&mut self, cwd: &Path) -> Result<()> {\n        #[cfg(unix)]\n        {","sourceCodeStart":1023,"sourceCodeEnd":1059,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp.rs#L1023-L1059","documentation":"On spawn, bind_file keeps the verified executable alive by passing it as an inherited file descriptor; it clears FD_CLOEXEC on the fd so the descriptor survives exec. This error is thrown when the fcntl calls to clear FD_CLOEXEC fail, so the verified descriptor cannot be handed to the child process. It aborts the launch rather than falling back to re-opening the path (which could have changed).","triggerScenarios":"bind_file (via prepare_stdio_launch or bind_command) bails when libc::fcntl(fd, F_GETFD) returns < 0 or F_SETFD clearing FD_CLOEXEC fails — i.e. the raw fd is invalid or the OS refused the descriptor-flag update.","commonSituations":"Exhausted or closed descriptors in the parent process; an unusual exec/parenting setup where the fd was closed before this point; container/OS security policies (seccomp, sandbox) blocking fcntl; platform-specific fd handling quirks.","solutions":["Check the process for fd leaks or premature fd closure (ulimit -n, lsof) and fix the leak or raise the descriptor limit","Run outside sandbox/seccomp policies that block fcntl, or add an allow rule for F_GETFD/F_SETFD","Report the failure with the OS/container details — if the launch path falls back to re-opening the file, that fallback must not bypass hash verification"],"exampleFix":"# before\n$ ulimit -n  # 64, too low, fcntl fails on new fds\n# after\n$ ulimit -n 1024  # or fix fd leak in parent; retry launching the plugin","handlingStrategy":"try-catch","validationCode":"# Before launch, confirm fd ops are permitted in this environment:\npython3 - <<'EOF'\nimport fcntl, os\nfd = os.open('/dev/null', os.O_RDONLY)\nflags = fcntl.fcntl(fd, fcntl.F_GETFD)\nfcntl.fcntl(fd, fcntl.F_SETFD, flags & ~fcntl.FD_CLOEXEC)\nprint('fcntl FD_CLOEXEC clearing works')\nEOF","typeGuard":null,"tryCatchPattern":"match launch_plugin() {\n    Err(e) if e.to_string().contains(\"failed to inherit reviewed plugin executable descriptor\") => {\n        eprintln!(\"fd inheritance blocked (fd limit? sandbox/seccomp?). Not falling back to re-open: integrity would be lost.\");\n        std::process::exit(1);\n    }\n    other => other.expect(\"plugin launch\"),\n}","preventionTips":["Raise RLIMIT_NOFILE and fix fd leaks in the launching process","Test plugin launching inside your sandbox/seccomp/container profile","Never bypass by re-opening the path — the descriptor exists precisely to prove reviewed bytes"],"tags":["unix","file-descriptor","fcntl","mcp","spawn"],"backgroundTag":"file-open-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}