python/cpython · error · ValueError
negative file descriptor
Error message
negative file descriptor
What it means
Raised by FileIO.__init__ when an integer file argument is less than zero. After the float rejection and the bool warning/conversion, an int fd is accepted only if it is >= 0; negative integers can never name an open file, so they fail fast before os.fstat is attempted.
Source
Thrown at Lib/_pyio.py:1555
# Have to close the existing file first.
self._stat_atopen = None
try:
if self._closefd:
os.close(self._fd)
finally:
self._fd = -1
if isinstance(file, float):
raise TypeError('integer argument expected, got float')
if isinstance(file, int):
if isinstance(file, bool):
import warnings
warnings.warn("bool is used as a file descriptor",
RuntimeWarning, stacklevel=2)
file = int(file)
fd = file
if fd < 0:
raise ValueError('negative file descriptor')
else:
fd = -1
if not isinstance(mode, str):
raise TypeError('invalid mode: %s' % (mode,))
if not set(mode) <= set('xrwab+'):
raise ValueError('invalid mode: %s' % (mode,))
if sum(c in 'rwax' for c in mode) != 1 or mode.count('+') > 1:
raise ValueError('Must have exactly one of create/read/write/append '
'mode and at most one plus')
if 'x' in mode:
self._created = True
self._writable = True
flags = os.O_EXCL | os.O_CREAT
elif 'r' in mode:
self._readable = True
flags = 0View on GitHub (pinned to bc6749cc3b)
Solutions
- Check the variable for the sentinel before using it as an fd: if fd < 0: raise/handle
- Initialize fd variables to None rather than -1 so misuse fails with a clearer error
- Ensure the earlier os.open/socket call actually succeeded and its return value (which raises on failure rather than returning -1 in Python) is what gets passed
Example fix
# before
fd = -1 # sentinel
...
f = open(fd, 'rb') # ValueError: negative file descriptor
# after
if fd is None or fd < 0:
raise RuntimeError('file descriptor was never opened')
f = open(fd, 'rb') Defensive patterns
Strategy: validation
Validate before calling
if isinstance(fd, bool) or not isinstance(fd, int):
raise TypeError('fd must be an int')
if fd < 0:
raise ValueError('negative file descriptor')
f = open(fd, 'rb') Type guard
def is_valid_fd(fd):
return isinstance(fd, int) and not isinstance(fd, bool) and fd >= 0 Try / catch
try:
f = open(fd, 'rb')
except ValueError as e:
if 'negative' in str(e):
fd = acquire_fd() # actually open/accept it
f = open(fd, 'rb')
else:
raise Prevention
- Initialize fd variables to None, never -1
- Check fd validity right after whatever produced it, before storing it
- Treat a negative fd as a bug in the producing code, not an input to handle
When it happens
Trigger: open(-1, 'rb'); passing a sentinel like -1 that an earlier os.dup()/socket() failure returned, or an uninitialized fd variable defaulting to a negative sentinel; index arithmetic that produced a negative value used as an fd.
Common situations: Code that stores fd = -1 as 'no fd yet' and later passes it to open() without checking whether the real fd was ever assigned; error paths where os.open returned and the -1 default leaked through; porting C code that used -1 sentinels.
Related errors
- integer argument expected, got float
- Must have exactly one of create/read/write/append mode and a
- Cannot use closefd=False with file name
- opener returned {fd}
- peek on closed file
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/a4adcbbc6c4ba82a.
Report an issue: GitHub.