GraphiteEditor/Graphite · error
Failed to create control channel
Error message
Failed to create control channel
What it means
Panic when ipc_channel::ipc::channel::<HostControlMessage>() fails. This call creates the OS-backed channel (socketpair on Unix, named pipe on Windows) that the host sends to the main process inside its Hello message for reverse-direction control messages. Channel creation fails when the process is out of file descriptors (EMFILE), when kernel object limits are hit, or when the sandbox blocks the underlying syscall.
Source
Thrown at desktop/ui/src/remote/host.rs:31
use crate::platform::mac;
pub(crate) fn run() {
// Ignore SIGINT, the controlling process is responsible for shutting down the host
#[cfg(any(target_os = "linux", target_os = "macos"))]
unsafe {
libc::signal(libc::SIGINT, libc::SIG_IGN);
}
let args: Vec<String> = std::env::args().collect();
let config = HostConfig::from_args(&args).expect("CEF host started without a valid host config argument");
let acceleration_requested = config.acceleration;
#[cfg(target_os = "macos")]
mac::spawn_parent_watchdog(config.main_pid);
let bootstrap = IpcSender::<EventMessage>::connect(config.server.clone()).expect("Failed to connect to the main process bootstrap server");
let event_sender = Arc::new(Mutex::new(bootstrap));
let (control_sender, control_receiver) = ipc_channel::ipc::channel::<HostControlMessage>().expect("Failed to create control channel");
#[cfg(feature = "accelerated_paint")]
let plane = if acceleration_requested { PlaneSender::from_config(&config, event_sender.clone()) } else { None };
#[cfg(feature = "accelerated_paint")]
let acceleration = plane.is_some();
#[cfg(not(feature = "accelerated_paint"))]
let acceleration = {
if acceleration_requested {
tracing::error!("UI acceleration requested but the accelerated_paint feature is disabled; using software frames");
}
false
};
event_sender
.lock()
.expect("The host message sender cannot be poisoned before threads exist")
.send(EventMessage::Hello {
pid: std::process::id(),View on GitHub (pinned to c507b35645)
Solutions
- Raise the file-descriptor limit for the app (ulimit -n before launch, LimitNOFILE= in systemd, --ulimit nofile= in docker)
- Inspect /proc/<host-pid>/fd to count open descriptors and find leaks if the failure appears over time
- Restart the app to release leaked descriptors and confirm the limit was the cause
- If sandboxed, allow the socketpair syscall family in the security policy
Example fix
# before (shell) ./graphite # host panics: Failed to create control channel # after ulimit -n 4096 ./graphite
Defensive patterns
Strategy: retry
Validate before calling
// Cheap canary: if fd count is near the limit, channel creation is likely to fail
fn fd_headroom(threshold: usize) -> bool {
let open = std::fs::read_dir("/proc/self/fd").map(|d| d.count()).unwrap_or(0);
open < threshold
} Try / catch
let (control_sender, control_receiver) = match ipc_channel::ipc::channel::<HostControlMessage>() {
Ok(ch) => ch,
Err(e) if e.to_string().contains("Too many open files") => {
std::thread::sleep(Duration::from_millis(50));
ipc_channel::ipc::channel::<HostControlMessage>().expect("control channel creation failed after retry")
}
Err(e) => panic!("Failed to create control channel: {e}"),
}; Prevention
- Launch the app with a generous file-descriptor limit (LimitNOFILE / ulimit -n 4096+)
- Track open descriptor counts in long sessions to catch leaks before they become panics
- Retry once on EMFILE-style errors; fd exhaustion can be transient under load
When it happens
Trigger: The UI host process exhausting its fd limit because many CEF browsers/pipes/sockets are open; a low ulimit -n in the service/container the host runs under; a seccomp/LD_PRELOAD sandbox interfering with socketpair creation.
Common situations: Long editor sessions accumulating leaked file descriptors; containers or systemd services started with LimitNOFILE low; heavy multi-window usage spawning many IPC channels; CI environments with restrictive rlimits.
Related errors
- Failed to connect to the main process bootstrap server
- Failed to spawn socket thread
- Failed to spawn the CEF control thread
- Failed to send Hello to the main process
- failed to construct async-message tokio runtime
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/289cb074d1be7cf5.
Report an issue: GitHub.