{"record":{"id":"e330f0e70982ec33","repo":"python/cpython","slug":"eisdir","errorCode":"EISDIR","errorMessage":"Is a directory","messagePattern":"Is a directory","errorType":"exception","errorClass":"IsADirectoryError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":1622,"sourceCode":"                    raise ValueError('Cannot use closefd=False with file name')\n                if opener is None:\n                    fd = os.open(file, flags, 0o666)\n                else:\n                    fd = opener(file, flags)\n                    if not isinstance(fd, int):\n                        raise TypeError('expected integer from opener')\n                    if fd < 0:\n                        # bpo-27066: Raise a ValueError for bad value.\n                        raise ValueError(f'opener returned {fd}')\n                owned_fd = fd\n                if not noinherit_flag:\n                    os.set_inheritable(fd, False)\n\n            self._closefd = closefd\n            self._stat_atopen = os.fstat(fd)\n            try:\n                if stat.S_ISDIR(self._stat_atopen.st_mode):\n                    raise IsADirectoryError(errno.EISDIR,\n                                            os.strerror(errno.EISDIR), file)\n            except AttributeError:\n                # Ignore the AttributeError if stat.S_ISDIR or errno.EISDIR\n                # don't exist.\n                pass\n\n            if _setmode:\n                # don't translate newlines (\\r\\n <=> \\n)\n                _setmode(fd, os.O_BINARY)\n\n            self.name = file\n            if self._appending:\n                # For consistent behaviour, we explicitly seek to the\n                # end of file (otherwise, it might be done only on the\n                # first write()).\n                try:\n                    os.lseek(fd, 0, SEEK_END)\n                except OSError as e:","sourceCodeStart":1604,"sourceCodeEnd":1640,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L1604-L1640","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nf = open(user_path, 'rb')  # user passed a directory -> IsADirectoryError\n\n# after\nfrom pathlib import Path\np = Path(user_path)\nif p.is_dir():\n    raise ValueError(f'{p} is a directory, expected a file')\nf = open(p, 'rb')","handlingStrategy":"validation","validationCode":"from pathlib import Path\np = Path(target)\nif p.is_dir():\n    raise ValueError(f'{p} is a directory, expected a file')\nf = open(p, 'rb')","typeGuard":"def is_file_not_dir(p):\n    from pathlib import Path\n    p = Path(p)\n    return p.exists() and not p.is_dir()","tryCatchPattern":"try:\n    f = open(path, 'rb')\nexcept IsADirectoryError:\n    logger.error('expected a file but got directory: %s', path)\n    raise","preventionTips":["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"],"tags":["python","io","file-io","eisdir","isadirectoryerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}