{"record":{"id":"cdcc7a1f3cb49efa","repo":"python/cpython","slug":"opener-returned-fd","errorCode":null,"errorMessage":"opener returned {fd}","messagePattern":"opener returned (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":1613,"sourceCode":"\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\n            if _setmode:\n                # don't translate newlines (\\r\\n <=> \\n)\n                _setmode(fd, os.O_BINARY)","sourceCodeStart":1595,"sourceCodeEnd":1631,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L1595-L1631","documentation":"Raised by FileIO.__init__ when a custom opener returns a negative integer (f-string 'opener returned {fd}'). Added for bpo-27066: previously a negative return was silently passed to os.fstat and produced a confusing failure, so it is now an explicit ValueError at the boundary.","triggerScenarios":"open(path, opener=lambda p, f: -1) or an opener that translates an internal failure into a -1 return (a C-style error convention) instead of raising.","commonSituations":"Openers wrapping C libraries or subprocess handles that use -1 as an error sentinel; openers that catch an exception internally and return -1 rather than propagating it; partial ports of C open() semantics.","solutions":["Raise an OSError (or let the original exception propagate) in the opener instead of returning -1","Validate the return right before handing it back: fd = ...; if fd < 0: raise OSError(...); return fd","Treat the opener contract strictly: it must return a valid non-negative open fd or raise"],"exampleFix":"# before\ndef opener(path, flags):\n    try:\n        return os.open(path, flags)\n    except OSError:\n        return -1                       # ValueError: opener returned -1\n\n# after\ndef opener(path, flags):\n    return os.open(path, flags)          # failures raise OSError directly","handlingStrategy":"validation","validationCode":"def checked_opener(path, flags):\n    fd = opener(path, flags)\n    if not isinstance(fd, int):\n        raise TypeError('expected integer from opener')\n    if fd < 0:\n        raise ValueError(f'opener returned {fd}')\n    return fd\nf = open(path, 'wb', opener=checked_opener)","typeGuard":null,"tryCatchPattern":"try:\n    f = open(path, 'wb', opener=opener)\nexcept ValueError as e:\n    if 'opener returned' in str(e):\n        f = open(path, 'wb')  # fall back to default os.open behavior\n    else:\n        raise","preventionTips":["Never return -1 from an opener; raise OSError instead","Wrap third-party openers with a validating adapter","Log opener return values during integration testing"],"tags":["python","io","file-io","opener","valueerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}