{"record":{"id":"e1fb7d9c907cafc3","repo":"juicedata/juicefs","slug":"can-only-commit-if-not-already-set-to-autocommit","errorCode":null,"errorMessage":"Can only commit if not already set to autocommit","messagePattern":"Can only commit if not already set to autocommit","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"sdk/python/juicefs/juicefs/spec.py","lineNumber":261,"sourceCode":"        self.__dict__.update(state)\n        if \"r\" in state[\"mode\"]:\n            self.f = None\n            self._open()\n            self.f.seek(loc)\n\n    def __getstate__(self):\n        d = self.__dict__.copy()\n        d.pop(\"f\")\n        if \"r\" in self.mode:\n            d[\"loc\"] = self.f.tell()\n        else:\n            if not self.f.closed:\n                raise ValueError(\"Cannot serialise open write-mode local file\")\n        return d\n\n    def commit(self):\n        if self.autocommit:\n            raise RuntimeError(\"Can only commit if not already set to autocommit\")\n        self.fs.fs.rename(self.temp, self.path)\n\n    def discard(self):\n        if self.autocommit:\n            raise RuntimeError(\"Can only commit if not already set to autocommit\")\n        self.fs.fs.remove(self.temp)\n\n    def tell(self):\n        return self.f.tell()\n\n    def seek(self, loc, whence=0):\n        return self.f.seek(loc, whence)\n\n    def write(self, data):\n        return self.f.write(data)\n\n    def read(self, length=-1):\n        return self.f.read(length)","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/sdk/python/juicefs/juicefs/spec.py#L243-L279","documentation":"LocalFile.commit() finalizes a write by renaming the temp file to its final path. If autocommit is enabled (default), the write was already committed, so calling commit() raises RuntimeError('Can only commit if not already set to autocommit').","triggerScenarios":"Calling f.commit() on a file opened with default autocommit=True; double-committing after a prior explicit commit; framework code that auto-commits on close then user code commits again.","commonSituations":"Explicit transaction-style code copied from fsspec examples without disabling autocommit; combining commit() with a with-block that auto-commits; migrating from manual-commit backends like s3fs to JuiceFS local files.","solutions":["Open with autocommit=False: fs.open(path, 'wb', autocommit=False) before calling commit()","Check f.autocommit and skip commit() when it is True","Rely on close() to finalize when using the default autocommit behavior"],"exampleFix":"// before\nf = fs.open('/mnt/jfs/out', 'wb')\nf.write(b'data')\nf.commit()  # RuntimeError\n// after\nf = fs.open('/mnt/jfs/out', 'wb', autocommit=False)\nf.write(b'data')\nf.commit()","handlingStrategy":"validation","validationCode":"if not f.autocommit:\n    f.commit()","typeGuard":null,"tryCatchPattern":"try:\n    f.commit()\nexcept RuntimeError as e:\n    if 'autocommit' in str(e):\n        pass  # already committed","preventionTips":["Open with autocommit=False when you want explicit commit()/discard() control","Check f.autocommit before transactional calls","Rely on close() to finalize under default autocommit"],"tags":["python","runtimeerror","autocommit","commit","localfile"],"backgroundTag":"invalid-state-transition","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}