{"record":{"id":"26fe796cd7bd4fe7","repo":"facebook/flow","slug":"daemon-set-context-bincode-serialize-context","errorCode":null,"errorMessage":"Daemon::set_context: bincode serialize context","messagePattern":"Daemon::set_context: bincode serialize context","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_daemon/src/daemon.rs","lineNumber":262,"sourceCode":"            .expect(\"Daemon::set_context: bincode serialize param\");\n        let context = Context {\n            parent_in_addr,\n            parent_out_addr,\n            token,\n            param_bytes,\n        };\n        // Include the PID in the prefix so that forked processes (which share\n        // OCaml's internal Filename PRNG state) generate distinct temp names.\n        let prefix = format!(\"daemon_param_{}_\", std::process::id());\n        let temp_dir = sys_utils::temp_dir_name();\n        let temp_file = NamedTempFile::with_prefix_in(&prefix, &temp_dir)?;\n        let path = temp_file.path().to_owned();\n        // Use `persist` to keep the file after `temp_file` drops; the child\n        // is responsible for deleting it (mirrors `daemon.ml:122\n        // `Sys.remove file` in `get_context`).\n        let (mut file, _path) = temp_file.keep().map_err(|e| e.error)?;\n        bincode::serde::encode_into_std_write(&context, &mut file, bincode::config::legacy())\n            .expect(\"Daemon::set_context: bincode serialize context\");\n        file.flush()?;\n        Ok(path)\n    }\n\n    // How this works on Unix: It may appear like we are passing file descriptors\n    // from one process to another here, but in_handle / out_handle are actually\n    // file descriptors that are already open in the current process -- they were\n    // created by the parent process before it did fork + exec. However, since\n    // exec causes the child to \"forget\" everything, we have to pass the numbers\n    // of these file descriptors as arguments.\n    //\n    // I'm not entirely sure what this does on Windows.\n    pub(crate) fn get_context() -> Option<(String, Context)> {\n        let entry = std::env::var(ENV_DAEMON).ok().filter(|s| !s.is_empty())?;\n        let file = std::env::var(ENV_DAEMON_PARAM)\n            .ok()\n            .filter(|s| !s.is_empty())?;\n        let bytes =","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_daemon/src/daemon.rs#L244-L280","documentation":"Panics when bincode cannot serialize the daemon startup context into the NamedTempFile created for it (daemon_param_<pid>_ in the temp dir). Context is statically Serialize, so the realistic failure is the I/O half of encode_into_std_write: the temp file is unwritable, deleted underneath the process, or the volume is full. The file is later read by the forked+exec'd child to reconstruct context.","triggerScenarios":"Calling Daemon::set_context (daemon spawn) when the temp dir reported by sys_utils::temp_dir_name is full (small tmpfs in a container); TMPDIR/TEMP points to a read-only or quota-limited location; a concurrent tmpwatcher/systemd-tmpfiles removes the daemon_param_* file between creation and write.","commonSituations":"Docker images with a tiny /tmp tmpfs; CI runners with exhausted disk quota; macOS automated tmp cleanup racing a slow spawn; TMPDIR inherited from a hardened service unit pointing somewhere non-writable.","solutions":["Free space in or enlarge the temp volume (/tmp tmpfs size, disk quota), or set TMPDIR to a writable location with headroom","Retry the spawn: the temp file is per-PID prefixed, so a fresh attempt creates a new file","Check ulimit -f (file size limit) and permissions on the temp dir if it persists"],"exampleFix":"// before — panics inside set_context on a full temp dir\nlet ctx_path = daemon::set_context(&context, &handles)?;\n\n// after — probe the temp dir first, give an actionable error\nlet tmp = sys_utils::temp_dir_name();\nif tempfile::NamedTempFile::new_in(&tmp).is_err() {\n    return Err(anyhow::anyhow!(\"temp dir {tmp:?} not writable; set TMPDIR\"));\n}\nlet ctx_path = daemon::set_context(&context, &handles)?;","handlingStrategy":"validation","validationCode":"// Probe the temp dir before spawning the daemon\nlet tmp = sys_utils::temp_dir_name();\nif tempfile::NamedTempFile::new_in(&tmp).is_err() {\n    return Err(anyhow::anyhow!(\"temp dir {tmp:?} not writable/full; set TMPDIR\"));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep headroom on the volume backing the temp dir; monitor free space","Set TMPDIR explicitly in containers to a writable, adequately sized path","Disable aggressive tmp cleaners (systemd-tmpfiles) for the daemon_param_* prefix"],"tags":["rust","bincode","tempfile","disk-full","io","daemon"],"backgroundTag":"temp-file-write-failed","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}