OSError: [Errno 28] No space left on device in Python (tested)
OSError: [Errno 28] No space left on device (ENOSPC) means the filesystem you are writing to is full. Because writes are buffered it can be raised by close() instead of write(), and it leaves a truncated file behind. Check with shutil.disk_usage, catch errno.ENOSPC, delete the partial file, and move temp files with TMPDIR.
Every block below ran in Docker with /data mounted as a 1 MB tmpfs (--tmpfs /data:size=1m), so the disk really fills up.
1. The error
# /data is a 1 MB tmpfs
with open("/data/big.bin", "wb") as f:
f.write(b"x" * 2_000_000)
Output:
Traceback (most recent call last):
File "/w/b1.py", line 3, in <module>
f.write(b"x" * 2_000_000)
~~~~~~~^^^^^^^^^^^^^^^^^^
OSError: [Errno 28] No space left on device
ENOSPC means the filesystem the file lives on has no free blocks left. It is about that filesystem only: /tmp, a Docker volume or a small root partition can be full while another disk has plenty of room.
2. It can surface at close(), not at write()
import os, shutil
print(shutil.disk_usage("/data"))
# the error often appears at close()/flush(), not at write()
f = open("/data/a.bin", "wb")
n = f.write(b"x" * 900_000)
print("write() returned", n)
f2 = open("/data/b.bin", "wb")
f2.write(b"y" * 200_000)
print("second write() did not raise")
try:
f2.close()
except OSError as e:
print("close():", type(e).__name__, e)
f.close()
for p in ("/data/a.bin", "/data/b.bin"):
print(p, os.path.getsize(p))
Output:
usage(total=1048576, used=0, free=1048576)
write() returned 900000
second write() did not raise
close(): OSError [Errno 28] No space left on device
/data/a.bin 900000
/data/b.bin 147456
Python buffers writes. The second write() did not raise even though only part of the data fit; the error appeared at close() when the buffer was flushed, and b.bin was left truncated at 147456 bytes. Code that only wraps write() in try misses it; wrap the whole with block, and treat a failed close() as a failed write.
3. Check free space first with shutil.disk_usage
import shutil
total, used, free = shutil.disk_usage("/data")
print(f"total={total} used={used} free={free}")
def ensure_space(path, need):
free = shutil.disk_usage(path).free
if free < need:
raise RuntimeError(f"need {need} bytes, only {free} free on {path}")
try:
ensure_space("/data", 2_000_000)
except RuntimeError as e:
print(e)
Output:
total=1048576 used=0 free=1048576
need 2000000 bytes, only 1048576 free on /data
shutil.disk_usage(path) returns total, used and free bytes for the filesystem that contains path. Checking before a large download or export gives a clear message instead of a half-written file. It is a hint, not a guarantee: other processes can fill the disk in between.
4. Handle it: catch ENOSPC and delete the partial file
import errno, os
path = "/data/out.bin"
try:
with open(path, "wb") as f:
f.write(b"z" * 2_000_000)
except OSError as e:
if e.errno != errno.ENOSPC:
raise
print("disk full:", errno.errorcode[e.errno])
print("partial file left behind:", os.path.getsize(path), "bytes")
os.remove(path)
print("removed:", not os.path.exists(path))
Output:
disk full: ENOSPC
partial file left behind: 1048576 bytes
removed: True
A failed write leaves a partial file that uses up the last free space. Remove it (or write to a temporary name and os.replace it into place only after a successful close) so the next run does not start on a full disk.
5. /tmp is full: point TMPDIR somewhere bigger
import tempfile
print(tempfile.gettempdir())
Output of python3 b5.py, then TMPDIR=/data python3 b5.py:
/tmp
/data
tempfile uses $TMPDIR when it is set, so moving temporary files to a larger disk is one environment variable, no code change. Then free space properly: find what is big with du -sh /path/* | sort -h, and on Docker hosts see Docker: no space left on device.
Related: [Errno 36] File name too long · [Errno 16] Device or resource busy · [Errno 13] Permission denied.
Frequently asked questions
Why do I get No space left on device when df shows free space?
The error is about the filesystem the path is on. Check shutil.disk_usage(path) or df on that exact path; /tmp, a container's overlay or a small volume can be full while other disks are not.
Why did close() raise Errno 28?
Python buffers writes, so data that did not fit is only written when the buffer is flushed at close(). Wrap the whole with block in try/except.
How do I catch Errno 28?
except OSError as e: if e.errno == errno.ENOSPC. There is no dedicated subclass.
Written with AI assistance. Measured on 2026-10-23 with Python 3.14.7 (python:3-alpine) in Docker with a 1 MB tmpfs mounted at /data. Each block was run verbatim and the output pasted unedited. PlainTables is our extension; Python and Docker are free.