{"record":{"id":"86705ecfafd67d32","repo":"juicedata/juicefs","slug":"i-o-operation-on-closed-file","errorCode":null,"errorMessage":"I/O operation on closed file.","messagePattern":"I/O operation on closed file\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdk/python/juicefs/juicefs/juicefs.py","lineNumber":607,"sourceCode":"\n    def flush(self):\n        return\n\n    def fsync(self):\n        self.lib.jfs_fsync(c_int64(_tid()), c_int32(self.fd))\n\n    def close(self):\n        if self.closed:\n            return\n        self.lib.jfs_close(c_int64(_tid()), c_int32(self.fd))\n        self.closed = True\n\n    def __del__(self):\n        self.close()\n\n    def _check_closed(self):\n        if self.closed:\n            raise ValueError('I/O operation on closed file.')\n\n    def readline(self): # TODO: add parameter `size=-1`\n        \"\"\"Read until newline or EOF.\"\"\"\n        ls = self.readlines(1)\n        if ls:\n            return ls[0]\n        return b''\n\n    def xreadlines(self):\n        return self\n\n    def readlines(self, hint=-1):\n        \"\"\"Return a list of lines from the stream.\"\"\"\n        self._check_closed()\n        if hint == -1:\n            data = self.read(-1)\n        else:\n            rs = []","sourceCodeStart":589,"sourceCodeEnd":625,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/sdk/python/juicefs/juicefs/juicefs.py#L589-L625","documentation":"_check_closed() raises ValueError('I/O operation on closed file.') whenever any I/O method (read, write, seek, tell, truncate, readlines) is used after close() has run (explicitly or via __del__/context exit).","triggerScenarios":"Calling f.read() after f.close(); using the file object outside a with-block after it was garbage collected; keeping a reference past a with statement and re-reading; double-close followed by use.","commonSituations":"Storing file handles in long-lived objects/dicts and reusing them later; functions returning closed handles; exception paths that close the file then retry reads.","solutions":["Reopen the file with juicefs.open() before further I/O","Move the I/O inside the with-block that owns the file","Check f.closed before operating on the handle"],"exampleFix":"// before\nf = juicefs.open(p, 'rb')\nf.close()\ndata = f.read()\n// after\nwith juicefs.open(p, 'rb') as f:\n    data = f.read()\nif f.closed:\n    f = juicefs.open(p, 'rb')\ndata = f.read()","handlingStrategy":"try-catch","validationCode":"if f.closed:\n    f = juicefs.open(f.path, f.mode)","typeGuard":null,"tryCatchPattern":"try:\n    data = f.read()\nexcept ValueError as e:\n    if 'closed file' in str(e):\n        f = juicefs.open(path, 'rb')\n        data = f.read()\n    else:\n        raise","preventionTips":["Always use with-blocks to scope file handles","Never store handles beyond their owning scope","Check f.closed before reuse"],"tags":["python","valueerror","closed-file","lifecycle"],"backgroundTag":"unsupported-operation","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}