{"record":{"id":"05860ba060246076","repo":"tokio-rs/tokio","slug":"not-a-pipe","errorCode":null,"errorMessage":"not a pipe","messagePattern":"not a pipe","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"tokio/src/net/unix/pipe.rs","lineNumber":275,"sourceCode":"        Sender::from_file_unchecked(file)\n    }\n\n    fn open(&self, path: &Path, pipe_end: PipeEnd) -> io::Result<File> {\n        let mut options = std::fs::OpenOptions::new();\n        options\n            .read(pipe_end == PipeEnd::Receiver)\n            .write(pipe_end == PipeEnd::Sender)\n            .custom_flags(libc::O_NONBLOCK);\n\n        #[cfg(any(target_os = \"linux\", target_os = \"android\"))]\n        if self.read_write {\n            options.read(true).write(true);\n        }\n\n        let file = options.open(path)?;\n\n        if !self.unchecked && !is_pipe(file.as_fd())? {\n            return Err(io::Error::new(io::ErrorKind::InvalidInput, \"not a pipe\"));\n        }\n\n        Ok(file)\n    }\n}\n\nimpl Default for OpenOptions {\n    fn default() -> OpenOptions {\n        OpenOptions::new()\n    }\n}\n\n#[derive(Clone, Copy, PartialEq, Eq, Debug)]\nenum PipeEnd {\n    Sender,\n    Receiver,\n}\n","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/tokio-rs/tokio/blob/625954f365727668cb02d04172b34f1149637728/tokio/src/net/unix/pipe.rs#L257-L293","documentation":"OpenOptions::open opens the path then, when unchecked is false, calls is_pipe on the resulting fd; if it isn't a FIFO, returns InvalidInput 'not a pipe'. The check exists because tokio's pipe sender/receiver require an actual FIFO — a regular file, socket, or character device will not behave correctly with non-blocking I/O.","triggerScenarios":"Calling OpenOptions::open_sender/open_receiver (or the internal open) on a path that does not resolve to a FIFO special file.unchecked=true bypasses the check.","commonSituations":"Pointing tokio::net::unix::pipe at a regular file or directory by mistake; passing a Unix-domain socket path; the FIFO hasn't been created yet (mkfifo not run); wrong path/typo.","solutions":["Ensure the path was created with mkfifo(1) / nix::unistd::mkfifo before opening.","If you genuinely have a pipe-like fd that fails the stat check, set .unchecked(true) on the OpenOptions — but only if you understand the risk.","Verify S_IFIFO via stat before opening and produce a clearer error.","Check the path for typos and that the FIFO still exists (it may have been removed)."],"exampleFix":"// before\nlet s = OpenOptions::new().open_sender(\"/tmp/log.txt\")?; // regular file\n\n// after\nuse nix::unistd::{mkfifo, Mode};\nlet _ = mkfifo(\"/tmp/log.fifo\", Mode::S_IRWXU);\nlet s = OpenOptions::new().open_sender(\"/tmp/log.fifo\")?;","handlingStrategy":"validation","validationCode":"use std::os::unix::fs::FileTypeExt;\nlet meta = std::fs::metadata(path)?;\nif !meta.file_type().is_fifo() {\n    return Err(anyhow::anyhow!(\"{path:?} is not a FIFO\"));\n}\n// then:\nOpenOptions::new().open_sender(path)?;","typeGuard":"fn is_not_a_pipe(e: &io::Error) -> bool {\n    e.kind() == io::ErrorKind::InvalidInput && e.to_string().contains(\"not a pipe\")\n}","tryCatchPattern":"match OpenOptions::new().open_sender(path) {\n    Ok(s) => Ok(s),\n    Err(e) if e.kind() == io::ErrorKind::InvalidInput => {\n        Err(anyhow::anyhow!(\"{path:?} is not a FIFO; run mkfifo first\"))\n    }\n    Err(e) => Err(e.into()),\n}","preventionTips":["Create the FIFO with mkfifo(1) or nix::unistd::mkfifo before opening.","Stat the path and assert S_IFIFO before handing it to OpenOptions.","Reserve .unchecked(true) for advanced cases where you accept the risk.","Verify the path still exists — FIFOs can be removed out of band."],"tags":["unix","pipe","fifo","filesystem","tokio"],"backgroundTag":null,"analyzedSha":"625954f365727668cb02d04172b34f1149637728","analyzedAt":"2026-08-11T17:46:45.378Z","contentChangedAt":"2026-08-11T17:46:45.378Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}