{"record":{"id":"b961fa731819968d","repo":"databendlabs/databend","slug":"writev-returned-zero-bytes","errorCode":null,"errorMessage":"writev returned zero bytes","messagePattern":"writev returned zero bytes","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/common/base/src/base/dma.rs","lineNumber":717,"sourceCode":"    }\n\n    pub fn flush_and_close(&mut self, mut file: SyncDmaFile) -> io::Result<usize> {\n        self.flush_inner(&mut file, true)?;\n        Ok(file.length())\n    }\n\n    pub fn flush(&mut self, file: &mut SyncDmaFile) -> io::Result<()> {\n        self.flush_inner(file, false)\n    }\n}\n\nfn writev_all(fd: impl AsFd, mut slices: &mut [IoSlice<'_>], offset: usize) -> io::Result<usize> {\n    let mut written = 0;\n\n    while !slices.is_empty() {\n        match rustix::io::pwritev(fd.as_fd(), slices, (offset + written) as _) {\n            Ok(0) => {\n                return Err(io::Error::new(\n                    io::ErrorKind::WriteZero,\n                    \"writev returned zero bytes\",\n                ));\n            }\n            Ok(n) => {\n                written += n;\n                IoSlice::advance_slices(&mut slices, n);\n            }\n            Err(err) => {\n                if err.kind() == io::ErrorKind::Interrupted {\n                    continue;\n                }\n                return Err(err.into());\n            }\n        };\n    }\n\n    Ok(written)","sourceCodeStart":699,"sourceCodeEnd":735,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/common/base/src/base/dma.rs#L699-L735","documentation":"`writev_all` writes multiple I/O slices with `pwritev` at a given offset, looping until all slices are consumed. A `pwritev` returning 0 means no bytes were written and no progress is possible, so it aborts with `ErrorKind::WriteZero` to avoid an infinite loop. Reached via `flush_if_full`/`flush_inner` when flushing buffered DMA writes.","triggerScenarios":"During buffer flush, `rustix::io::pwritev` returns `Ok(0)` — no bytes accepted by the kernel for the aligned offset, e.g. disk full at EOF, filesystem oddity, or an invalid fd state.","commonSituations":"Disk/quota exhaustion, writes to a file on a filesystem with broken vectored-I/O support, file truncated concurrently by another process, O_DIRECT incompatibility with the buffer alignment.","solutions":["Check free disk space and quotas on the target device (`df -h`, project quotas).","Confirm the mount supports O_DIRECT + pwritev correctly (ext4/xfs are safe; some network/FUSE filesystems are not).","Ensure no concurrent truncation of the data file by other processes.","Retry the write; if deterministic, fall back to non-direct I/O or re-align buffers."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// check disk headroom before flushing\nfn has_headroom(dir: &Path, need: u64) -> std::io::Result<bool> {\n    Ok(fs2::available_space(dir)? > need)\n}","typeGuard":null,"tryCatchPattern":"match writer.flush() {\n    Err(e) if e.kind() == std::io::ErrorKind::WriteZero => handle_flush_failure(e), // disk full / fs issue\n    other => other,\n}","preventionTips":["Monitor free space on the data volume","Use filesystems with solid pwritev + O_DIRECT support","Avoid external truncation of in-use files"],"tags":["io","direct-io","writev"],"backgroundTag":"file-write-failed","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}