python/cpython · error · ValueError

Cannot use closefd=False with file name

Error message

Cannot use closefd=False with file name

What it means

Raised by FileIO.__init__ when a path (not an fd) is given together with closefd=False. closefd only has meaning for integer file descriptors — when FileIO opens the file itself from a name, it owns the resulting fd and must be able to close it; refusing closefd=False prevents a leaked fd that nothing else can manage.

Source

Thrown at Lib/_pyio.py:1604

        if self._readable and self._writable:
            flags |= os.O_RDWR
        elif self._readable:
            flags |= os.O_RDONLY
        else:
            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,

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Drop closefd (or pass closefd=True) when opening by path — True is already the default
  2. Only use closefd=False when passing an integer fd you want to keep open after the object is closed
  3. In wrapper APIs, set closefd only for the fd branch: closefd=closefd if isinstance(file, int) else None

Example fix

# before
f = open('data.bin', 'rb', closefd=False)  # ValueError

# after
f = open('data.bin', 'rb')                # closefd defaults to True for paths
# closefd=False is only valid like this:
g = open(fd, 'rb', closefd=False)
Defensive patterns

Strategy: validation

Validate before calling

import os
kwargs = {}
if isinstance(file_arg, int) and not isinstance(file_arg, bool):
    kwargs['closefd'] = closefd   # only meaningful for real fds
f = open(file_arg, 'rb', **kwargs)

Type guard

def closefd_allowed(file):
    return isinstance(file, int) and not isinstance(file, bool)

Try / catch

try:
    f = open(path, 'rb', closefd=closefd)
except ValueError as e:
    if 'closefd' in str(e):
        f = open(path, 'rb')  # retry with default closefd=True
    else:
        raise

Prevention

When it happens

Trigger: open(path, 'rb', closefd=False); io.FileIO('data.txt', 'r', closefd=False). Any call where file is a str/bytes/PathLike and closefd is falsy hits this branch because fd < 0 at that point.

Common situations: Copy-pasting closefd=False from code that wrapped an existing fd; wrapping a path-based helper that forwards **kwargs including closefd; library APIs that expose closefd for both fd and path inputs without branching.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/9a07226e89563541. Report an issue: GitHub.