python/cpython · error · ValueError
opener returned {fd}
Error message
opener returned {fd} What it means
Raised by FileIO.__init__ when a custom opener returns a negative integer (f-string 'opener returned {fd}'). Added for bpo-27066: previously a negative return was silently passed to os.fstat and produced a confusing failure, so it is now an explicit ValueError at the boundary.
Source
Thrown at Lib/_pyio.py:1613
noinherit_flag = (getattr(os, 'O_NOINHERIT', 0) or
getattr(os, 'O_CLOEXEC', 0))
flags |= noinherit_flag
owned_fd = None
try:
if fd < 0:
if not closefd:
raise ValueError('Cannot use closefd=False with file name')
if opener is None:
fd = os.open(file, flags, 0o666)
else:
fd = opener(file, flags)
if not isinstance(fd, int):
raise TypeError('expected integer from opener')
if fd < 0:
# bpo-27066: Raise a ValueError for bad value.
raise ValueError(f'opener returned {fd}')
owned_fd = fd
if not noinherit_flag:
os.set_inheritable(fd, False)
self._closefd = closefd
self._stat_atopen = os.fstat(fd)
try:
if stat.S_ISDIR(self._stat_atopen.st_mode):
raise IsADirectoryError(errno.EISDIR,
os.strerror(errno.EISDIR), file)
except AttributeError:
# Ignore the AttributeError if stat.S_ISDIR or errno.EISDIR
# don't exist.
pass
if _setmode:
# don't translate newlines (\r\n <=> \n)
_setmode(fd, os.O_BINARY)View on GitHub (pinned to bc6749cc3b)
Solutions
- Raise an OSError (or let the original exception propagate) in the opener instead of returning -1
- Validate the return right before handing it back: fd = ...; if fd < 0: raise OSError(...); return fd
- Treat the opener contract strictly: it must return a valid non-negative open fd or raise
Example fix
# before
def opener(path, flags):
try:
return os.open(path, flags)
except OSError:
return -1 # ValueError: opener returned -1
# after
def opener(path, flags):
return os.open(path, flags) # failures raise OSError directly Defensive patterns
Strategy: validation
Validate before calling
def checked_opener(path, flags):
fd = opener(path, flags)
if not isinstance(fd, int):
raise TypeError('expected integer from opener')
if fd < 0:
raise ValueError(f'opener returned {fd}')
return fd
f = open(path, 'wb', opener=checked_opener) Try / catch
try:
f = open(path, 'wb', opener=opener)
except ValueError as e:
if 'opener returned' in str(e):
f = open(path, 'wb') # fall back to default os.open behavior
else:
raise Prevention
- Never return -1 from an opener; raise OSError instead
- Wrap third-party openers with a validating adapter
- Log opener return values during integration testing
When it happens
Trigger: open(path, opener=lambda p, f: -1) or an opener that translates an internal failure into a -1 return (a C-style error convention) instead of raising.
Common situations: Openers wrapping C libraries or subprocess handles that use -1 as an error sentinel; openers that catch an exception internally and return -1 rather than propagating it; partial ports of C open() semantics.
Related errors
- negative file descriptor
- Must have exactly one of create/read/write/append mode and a
- Cannot use closefd=False with file name
- expected integer from opener
- peek on closed file
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/cdcc7a1f3cb49efa.
Report an issue: GitHub.