python/cpython · error · TypeError
expected integer from opener
Error message
expected integer from opener
What it means
Raised by FileIO.__init__ when a custom opener callable returns a value that is not an int. The opener protocol (PEP 443-era feature used by open(file, opener=...)) requires opener(path, flags) -> int fd; anything else (float, None, a tuple, an int subclass like bool aside) is rejected with TypeError before the fd is used.
Source
Thrown at Lib/_pyio.py:1610
flags |= os.O_WRONLY
flags |= getattr(os, 'O_BINARY', 0)
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
View on GitHub (pinned to bc6749cc3b)
Solutions
- Make the opener return the raw int fd: def opener(path, flags): return os.open(path, flags, 0o600)
- Return the fd on every code path, including error paths (or raise OSError yourself instead of returning a sentinel)
- If delegating, unwrap the integer: return wrapper.fileno()
Example fix
# before
def opener(path, flags):
os.open(path, flags) # forgot return -> returns None
f = open('f.bin', 'wb', opener=opener) # TypeError: expected integer from opener
# after
def opener(path, flags):
return os.open(path, flags, 0o600)
f = open('f.bin', 'wb', opener=opener) Defensive patterns
Strategy: type-guard
Validate before calling
fd = opener(file, flags)
if not isinstance(fd, int) or isinstance(fd, bool):
raise TypeError('expected integer from opener')
if fd < 0:
raise ValueError(f'opener returned {fd}') Type guard
def opener_returns_int(fn):
# smoke-test the opener once with a harmless call signature in tests
return callable(fn) Try / catch
try:
f = open(path, 'wb', opener=opener)
except TypeError as e:
if 'opener' in str(e):
def fixed_opener(p, flags):
return int(opener(p, flags))
f = open(path, 'wb', opener=fixed_opener)
else:
raise Prevention
- Opener contract: opener(path, flags) -> non-negative int or raise
- Add a unit test for every custom opener asserting the return type
- Use linters/strict typing (mypy) on opener implementations
When it happens
Trigger: open(path, 'wb', opener=lambda p, f: os.open(p, f) if cond else None); an opener returning a numpy integer or a dataclass wrapping the fd; an opener that forgets to return and yields None.
Common situations: Custom openers implementing sandboxing/permission checks that return a status code or (fd, error) tuple instead of a bare fd; openers delegating to wrappers (e.g. os.fdopen results, which are file objects, not ints); missing return statement after an early-exit branch.
Related errors
- integer argument expected, got float
- invalid mode: %s
- opener returned {fd}
- an integer is required
- negative file descriptor
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/5ad19edee94ba985.
Report an issue: GitHub.