{"record":{"id":"5ad19edee94ba985","repo":"python/cpython","slug":"expected-integer-from-opener","errorCode":null,"errorMessage":"expected integer from opener","messagePattern":"expected integer from opener","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":1610,"sourceCode":"            flags |= os.O_WRONLY\n\n        flags |= getattr(os, 'O_BINARY', 0)\n\n        noinherit_flag = (getattr(os, 'O_NOINHERIT', 0) or\n                          getattr(os, 'O_CLOEXEC', 0))\n        flags |= noinherit_flag\n\n        owned_fd = None\n        try:\n            if fd < 0:\n                if not closefd:\n                    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","sourceCodeStart":1592,"sourceCodeEnd":1628,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L1592-L1628","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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()"],"exampleFix":"# before\ndef opener(path, flags):\n    os.open(path, flags)          # forgot return -> returns None\nf = open('f.bin', 'wb', opener=opener)  # TypeError: expected integer from opener\n\n# after\ndef opener(path, flags):\n    return os.open(path, flags, 0o600)\nf = open('f.bin', 'wb', opener=opener)","handlingStrategy":"type-guard","validationCode":"fd = opener(file, flags)\nif not isinstance(fd, int) or isinstance(fd, bool):\n    raise TypeError('expected integer from opener')\nif fd < 0:\n    raise ValueError(f'opener returned {fd}')","typeGuard":"def opener_returns_int(fn):\n    # smoke-test the opener once with a harmless call signature in tests\n    return callable(fn)","tryCatchPattern":"try:\n    f = open(path, 'wb', opener=opener)\nexcept TypeError as e:\n    if 'opener' in str(e):\n        def fixed_opener(p, flags):\n            return int(opener(p, flags))\n        f = open(path, 'wb', opener=fixed_opener)\n    else:\n        raise","preventionTips":["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"],"tags":["python","io","file-io","opener","typeerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}