{"record":{"id":"c5d3ca0398ec761d","repo":"python/cpython","slug":"file-or-stream-is-not-writable","errorCode":null,"errorMessage":"File or stream is not writable.","messagePattern":"File or stream is not writable\\.","errorType":"exception","errorClass":"UnsupportedOperation","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":462,"sourceCode":"    def _checkReadable(self, msg=None):\n        \"\"\"Internal: raise UnsupportedOperation if file is not readable\n        \"\"\"\n        if not self.readable():\n            raise UnsupportedOperation(\"File or stream is not readable.\"\n                                       if msg is None else msg)\n\n    def writable(self):\n        \"\"\"Return a bool indicating whether object was opened for writing.\n\n        If False, write() and truncate() will raise OSError.\n        \"\"\"\n        return False\n\n    def _checkWritable(self, msg=None):\n        \"\"\"Internal: raise UnsupportedOperation if file is not writable\n        \"\"\"\n        if not self.writable():\n            raise UnsupportedOperation(\"File or stream is not writable.\"\n                                       if msg is None else msg)\n\n    @property\n    def closed(self):\n        \"\"\"closed: bool.  True iff the file has been closed.\n\n        For backwards compatibility, this is a property, not a predicate.\n        \"\"\"\n        return self.__closed\n\n    def _checkClosed(self, msg=None):\n        \"\"\"Internal: raise a ValueError if file is closed\n        \"\"\"\n        if self.closed:\n            raise ValueError(\"I/O operation on closed file.\"\n                             if msg is None else msg)\n\n    ### Context manager ###","sourceCodeStart":444,"sourceCodeEnd":480,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L444-L480","documentation":"Raised by IOBase._checkWritable() as io.UnsupportedOperation when write() (and writelines/truncate) is called on a stream whose writable() returns False — a stream opened read-only. Like 178, it enforces the open mode at call time for every IOBase-derived stream (files, sockets wrappers, BytesIO from binary payloads, etc.).","triggerScenarios":"open('in.txt', 'r').write('x'); writing to p.stdout of a Popen you read from (stdout is a read pipe); calling .write() on a GzipFile opened 'rb'; attempts to log into a handle received in read mode; io.BytesIO(read_only_bytes).write().","commonSituations":"Functions that accept 'a stream' and write to it, invoked with an accidentally read-mode handle; refactoring that changes an open('w') to open('r') for inspection and forgetting to revert; read-only resources (files without write permission are a different OSError, but read-mode opens are this one).","solutions":["Open the target for writing: 'w', 'a' (append), 'x' (exclusive create), or 'r+' to extend in place.","Guard in generic code: if stream.writable(): stream.write(...) else raise/handle.","Separate concerns: pass a dedicated write handle to writers instead of reusing input handles.","For in-memory mutation, use a fresh io.BytesIO()/io.StringIO() in its default read-write-capable state."],"exampleFix":"// before\nwith open('note.txt', 'r') as f:\n    f.write('update')      # UnsupportedOperation: not writable\n\n// after\nwith open('note.txt', 'a') as f:\n    f.write('update')      # append, or 'r+' + seek for in-place edit","handlingStrategy":"type-guard","validationCode":"if stream.writable():\n    stream.write(data)\nelse:\n    raise ValueError(f'{stream!r} is not open for writing')","typeGuard":"def is_writable(stream) -> bool:\n    probe = getattr(stream, 'writable', None)\n    return callable(probe) and probe()","tryCatchPattern":"import io\n\ntry:\n    sink.write(line)\nexcept io.UnsupportedOperation:\n    with open(path, 'a', encoding='utf-8') as real_sink:\n        real_sink.write(line)","preventionTips":["Give writers their own handle opened 'w'/'a'/'x'; never reuse input handles.","In APIs accepting streams, check stream.writable() up front and raise a clear domain error.","Re-check mode strings after switching opens between 'r' and 'w' during debugging."],"tags":["io","stream","write","mode","unsupported-operation"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}