python/cpython · error · IsADirectoryError
EISDIR
EISDIR
Error message
Is a directory
What it means
Raised by FileIO.__init__ after a successful open when os.fstat() shows the target's st_mode is a directory (S_ISDIR). Opening a directory path for reading/writing succeeds at the OS level on many platforms, so CPython detects it explicitly and raises IsADirectoryError with errno EISDIR and the message from os.strerror(EISDIR) — 'Is a directory'.
Source
Thrown at Lib/_pyio.py:1622
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)
self.name = file
if self._appending:
# For consistent behaviour, we explicitly seek to the
# end of file (otherwise, it might be done only on the
# first write()).
try:
os.lseek(fd, 0, SEEK_END)
except OSError as e:View on GitHub (pinned to bc6749cc3b)
Solutions
- Check the path before opening: os.path.isfile(path) (or Path.is_file()) and report a clear error to the user
- Filter directory entries when iterating: if entry.is_dir(): continue
- Handle IsADirectoryError explicitly to give a better message than the default
Example fix
# before
f = open(user_path, 'rb') # user passed a directory -> IsADirectoryError
# after
from pathlib import Path
p = Path(user_path)
if p.is_dir():
raise ValueError(f'{p} is a directory, expected a file')
f = open(p, 'rb') Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
p = Path(target)
if p.is_dir():
raise ValueError(f'{p} is a directory, expected a file')
f = open(p, 'rb') Type guard
def is_file_not_dir(p):
from pathlib import Path
p = Path(p)
return p.exists() and not p.is_dir() Try / catch
try:
f = open(path, 'rb')
except IsADirectoryError:
logger.error('expected a file but got directory: %s', path)
raise Prevention
- Filter glob/scandir results with entry.is_file() before opening
- Validate user-supplied paths with Path.is_dir() at the CLI boundary
- Remember IsADirectoryError is an OSError subclass — catch it specifically
When it happens
Trigger: open('/some/dir', 'rb') or io.FileIO(dirpath, 'r'); globbing or walking a tree and opening every matched path without checking isdir(); user-supplied path pointing at a directory.
Common situations: Treating a directory path as a config/data file; os.scandir/glob results fed into open() unfiltered; scripts where the user passed the folder instead of the file inside it; TOCTOU where a file was replaced by a directory between check and open.
Related errors
- integer argument expected, got float
- negative file descriptor
- invalid mode: %s
- Must have exactly one of create/read/write/append mode and a
- Cannot use closefd=False with file name
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/e330f0e70982ec33.
Report an issue: GitHub.