{"record":{"id":"2cd3cd1636722b65","repo":"zellij-org/zellij","slug":"could-not-daemonize-the-server-process","errorCode":null,"errorMessage":"could not daemonize the server process","messagePattern":"could not daemonize the server process","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"zellij-server/src/lib.rs","lineNumber":864,"sourceCode":"        // After clear, removing the client yields no stuck tokens.\n        assert!(s.remove_client(1).is_empty());\n    }\n}\n\npub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {\n    info!(\"Starting Zellij server!\");\n\n    #[cfg(unix)]\n    {\n        use nix::sys::stat::{umask, Mode};\n        // preserve the current umask: read current value by setting to another mode, and then restoring it\n        let current_umask = umask(Mode::all());\n        umask(current_umask);\n        daemonize::Daemonize::new()\n            .working_directory(std::env::current_dir().unwrap())\n            .umask(current_umask.bits() as u32)\n            .start()\n            .expect(\"could not daemonize the server process\");\n    }\n\n    #[cfg(windows)]\n    {\n        // The server is spawned with CREATE_NEW_PROCESS_GROUP, which disables\n        // Ctrl+C handling for the process.  Child processes inherit this\n        // disabled state, so ConPTY children (shells, commands) would silently\n        // ignore CTRL_C_EVENT signals.  Re-enable Ctrl+C here so that\n        // descendants get the normal default handler (terminate on Ctrl+C).\n        //\n        use windows_sys::Win32::System::Console::SetConsoleCtrlHandler;\n        unsafe {\n            SetConsoleCtrlHandler(None, 0);\n        }\n    }\n\n    start_server_impl(os_input, socket_path, true);\n}","sourceCodeStart":846,"sourceCodeEnd":882,"githubUrl":"https://github.com/zellij-org/zellij/blob/98a0837077492d53dd252ab30bc3e43e41e504f4/zellij-server/src/lib.rs#L846-L882","documentation":"On unix the zellij server daemonizes before binding its sockets: fork, setsid, redirect stdio to /dev/null and chdir to the current working directory, explicitly preserving the inherited umask. The expect fires if any step fails - fork(2) EAGAIN at the process limit, chdir into a directory deleted after launch, or failure opening /dev/null. This happens during server bootstrap, so a new session cannot start.","triggerScenarios":"Starting or resuming a session when the launch directory no longer exists (ENOENT on chdir), the process limit blocks fork (EAGAIN), or /dev/null is missing/unwritable.","commonSituations":"Launching zellij from a temp dir, an unmounted share, or a deleted directory; heavily loaded build machines; containers with strict process limits or a broken /dev/null.","solutions":["Launch zellij from a stable existing directory such as $HOME","Raise the process limit (ulimit -u / systemd TasksMax) on the host","Verify /dev/null exists as character device 1:3 with mode 666; recreate it if broken","Retry session creation after fixing the environment; each start re-attempts daemonize"],"exampleFix":"// before\ndaemonize::Daemonize::new()\n    .working_directory(std::env::current_dir().unwrap())\n    .umask(current_umask.bits() as u32)\n    .start()\n    .expect(\"could not daemonize the server process\");\n\n// after - validate preconditions and fail with context\nlet cwd = std::env::current_dir().context(\"no current dir\").fatal();\nstd::fs::metadata(&cwd).context(\"cwd vanished before daemonize\").fatal();\ndaemonize::Daemonize::new()\n    .working_directory(cwd)\n    .umask(current_umask.bits() as u32)\n    .start()\n    .context(\"daemonize failed: fork limit, cwd, or /dev/null\")\n    .fatal();","handlingStrategy":"validation","validationCode":"// run before daemonizing\nuse std::os::unix::fs::FileTypeExt;\n\nfn daemonize_preconditions_ok() -> bool {\n    let cwd_ok = std::env::current_dir().map(|p| p.exists()).unwrap_or(false);\n    let devnull_ok = std::fs::metadata(\"/dev/null\")\n        .map(|m| m.file_type().is_char_device())\n        .unwrap_or(false);\n    cwd_ok && devnull_ok\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always start sessions from long-lived directories such as $HOME","Keep /dev/null intact in minimal containers (devtmpfs mounted)","Set TasksMax/RLIMIT_NPROC with headroom for the fork","Fail fast with a clear message if preconditions fail instead of expecting inside daemonize"],"tags":["rust","zellij","daemonize","unix","process-limits","server-startup"],"backgroundTag":null,"analyzedSha":"98a0837077492d53dd252ab30bc3e43e41e504f4","analyzedAt":"2026-08-16T13:02:01.396Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}