{"record":{"id":"9cbd1dd82c89a491","repo":"python/cpython","slug":"file-not-open-for-writing","errorCode":null,"errorMessage":"File not open for writing","messagePattern":"File not open for writing","errorType":"exception","errorClass":"UnsupportedOperation","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":1690,"sourceCode":"\n    @property\n    def _blksize(self):\n        if self._stat_atopen is None:\n            return DEFAULT_BUFFER_SIZE\n\n        blksize = getattr(self._stat_atopen, \"st_blksize\", 0)\n        # WASI sets blsize to 0\n        if not blksize:\n            return DEFAULT_BUFFER_SIZE\n        return blksize\n\n    def _checkReadable(self):\n        if not self._readable:\n            raise UnsupportedOperation('File not open for reading')\n\n    def _checkWritable(self, msg=None):\n        if not self._writable:\n            raise UnsupportedOperation('File not open for writing')\n\n    def read(self, size=None):\n        \"\"\"Read at most size bytes, returned as bytes.\n\n        If size is less than 0, read all bytes in the file making\n        multiple read calls. See ``FileIO.readall``.\n\n        Attempts to make only one system call, retrying only per\n        PEP 475 (EINTR). This means less data may be returned than\n        requested.\n\n        In non-blocking mode, returns None if no data is available.\n        Return an empty bytes object at EOF.\n        \"\"\"\n        self._checkClosed()\n        self._checkReadable()\n        if size is None or size < 0:\n            return self.readall()","sourceCodeStart":1672,"sourceCodeEnd":1708,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L1672-L1708","documentation":"Raised by FileIO._checkWritable as io.UnsupportedOperation('File not open for writing') when write/writelines/truncate is called on a FileIO whose mode never set the _writable flag (i.e. opened with 'r'/'rb' without '+'). The check fires before any syscall, so nothing is written and errno is not involved.","triggerScenarios":"f = open('in.txt','rb', buffering=0); f.write(b'data') — any write-family call on a read-only FileIO or the TextIOWrapper/BufferedReader stacked above it.","commonSituations":"Caching/append logic accidentally pointed at a handle opened for reading; code that opens everything 'rb' for safety then attempts telemetry writes; mixing up two variables (reader handle used where the writer was intended).","solutions":["Open the file with a write-capable mode ('wb', 'ab', 'r+b') for the handle that receives writes","Use separate handles: one 'rb' reader and one 'ab' writer for append-only logs","Fix the mode string in configuration if it is data-driven"],"exampleFix":"# before\nf = open('log.txt', 'rb')\nf.write(b'entry\\n')       # UnsupportedOperation: File not open for writing\n\n# after\nwith open('log.txt', 'ab') as f:\n    f.write(b'entry\\n')","handlingStrategy":"validation","validationCode":"def write_to(f, data):\n    if not f.writable():\n        raise io.UnsupportedOperation('File not open for writing')\n    return f.write(data)","typeGuard":"def is_writable_handle(f):\n    return not f.closed and f.writable()","tryCatchPattern":"try:\n    f.write(data)\nexcept io.UnsupportedOperation as e:\n    if 'writing' in str(e):\n        with open(f.name, 'ab') as g:  # reopen for append\n            g.write(data)\n    else:\n        raise","preventionTips":["Call f.writable() before writing through generic handles","Use dedicated append handles ('ab') for logging alongside read handles","Note io.UnsupportedOperation inherits from both OSError and ValueError — catch it by name"],"tags":["python","io","file-io","mode","unsupportedoperation"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}