databendlabs/databend · error
write returned zero bytes
Error message
write returned zero bytes
What it means
`write_direct` performs aligned `pwrite` calls on a DMA (O_DIRECT) file in a loop until all data is written. POSIX allows short writes, but a return of 0 bytes means no progress was made — treated as `ErrorKind::WriteZero`. Continuing would loop forever, so the code aborts with this io::Error.
Solutions
- Check disk space and quotas on the device holding the data file (`df -h`).
- Ensure the file was opened correctly for O_DIRECT and offsets/buffer are properly aligned (the code aligns offsets, but verify the mount supports O_DIRECT).
- Verify the fd is still valid and the file wasn't truncated concurrently by another process.
- Retry the operation; if it reproduces on a specific filesystem, test on a filesystem known to support O_DIRECT (ext4/xfs) or disable direct I/O if configurable.
Defensive patterns
Strategy: try-catch
Validate before calling
// before writing, check space and fd state
fn can_write(fd: &File, dir: &Path) -> std::io::Result<()> {
let meta = fs::metadata(dir)?;
let avail = fs2::available_space(dir)?;
if avail < meta.len() { return Err(std::io::Error::new(std::io::ErrorKind::StorageFull, "low disk")); }
Ok(())
} Try / catch
match writer.write_direct(&buf) {
Err(e) if e.kind() == std::io::ErrorKind::WriteZero => handle_disk_full_or_io_failure(e),
other => other,
} Prevention
- Monitor disk space and quotas on the data volume
- Verify the mount supports O_DIRECT
- Avoid concurrent truncation of active data files
When it happens
Trigger: `rustix::io::pwrite` on the direct-I/O file returns `Ok(0)`, e.g. at/behind EOF semantics on certain filesystems, a full disk returning zero, or the fd reaching an unexpected end condition mid-write.
Common situations: Disk full or quota exhausted on the backing device, filesystem not honoring O_DIRECT writes at the requested aligned offset, unusual fuse/network filesystems that return 0 instead of an error.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- writev returned zero bytes
- Expected to have bytes
- Expected to have insensitive bytes
- Expected to ignore a byte
- Fst data is corrupted
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/4c841c09eb7d5826.
Report an issue: GitHub.
Appendix: source
Thrown at src/common/base/src/base/dma.rs:234
pub fn align_down(&self, value: usize) -> usize {
self.alignment.align_down(value)
}
/// Return the alignment requirement for this file. The returned alignment value can be used
/// to allocate a buffer to use with this file:
pub fn alignment(&self) -> Alignment {
self.alignment
}
fn write_direct(&mut self, buf: &mut DmaBuffer) -> io::Result<usize> {
let data = buf.as_slice();
let mut written = 0;
let offset = self.align_down(self.offset);
while written < data.len() {
match rustix::io::pwrite(&self.fd, &data[written..], (offset + written) as _) {
Ok(0) => {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"write returned zero bytes",
));
}
Ok(n) => {
written += n;
self.offset = offset + written
}
Err(err) => {
if err.kind() == io::ErrorKind::Interrupted {
continue;
}
return Err(err.into());
}
}
}
buf.clear();
Ok(written)View on GitHub (pinned to 288d84d76e)