electron-store: Operation not permitted
Got the following error from Sentry produced by our production app. Could this be due to some odd permissions that the user has changed on their system?
OS: Windows 10.0.17763 Electron: 8.0.0 electron-store: 3.3.0
Error: EPERM: operation not permitted, rename 'C:\Users\mattd\AppData\Roaming\clockk\config.json.2393936311' -> 'C:\Users\mattd\AppData\Roaming\clockk\config.json'
at Function.writeFileSync [as sync](app:///node_modules/write-file-atomic/index.js:198:8)
at ElectronStore.set store [as store](app:///node_modules/conf/index.js:267:19)
at ElectronStore.set(app:///node_modules/conf/index.js:152:14)
at _.clearArtifacts(app://./js/app.1a7ce22d.js:1:20601)
at ? (app://./js/chunk-vendors.3f748be6.js:38:5706)
at ? (app://./js/chunk-vendors.3f748be6.js:38:6751)
at Array.forEach(<anonymous>)
at ? (app://./js/chunk-vendors.3f748be6.js:38:6730)
at _._withCommit(app://./js/chunk-vendors.3f748be6.js:38:8276)
at _.commit(app://./js/chunk-vendors.3f748be6.js:38:6704)
at _.commit [as originalCommit](app://./js/chunk-vendors.3f748be6.js:38:3374)
at EventEmitter.<anonymous>(app://./js/chunk-vendors.3f748be6.js:85:28802)
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 1
- Comments: 41 (4 by maintainers)
@sindresorhus Here we go (hopefully): https://github.com/fabiospampinato/atomically
I’m basically on your same boat and I couldn’t find anything better than
write-file-atomic
, so I rewrote it. I’d sayatomically
is probably strictly better thanwrite-file-atomic
, it handles more errors (including the one mentioned here), it can be 10x faster on synchronous writes and just as safe (I’ve no idea why in my benchmark it isn’t also 10x faster in asynchronous writes), it has way more options (including a way to hide temporary files) etc.On the code quality I can’t comment too much being the author of this one, but at least when putting the async and sync version of the provided functions side by side the implementation is basically identical, in
write-file-atomic
there are a bunch of quirks because this isn’t true there too. Unfortunately the test suite is still pretty messy as I inherited the one fromwrite-file-atomic
, but throwing their tests away didn’t feel right and rewriting the entire test suite didn’t feel worth it.Happy to work on any eventual issue you guys can find, I’m going to use this library in an Electron app too so any issue you can find I’ll be interested in fixing it.
I’ve been doing some research. I think it boils down to the fact that Windows API for rename is very unstable and depends on a lot of factors like anti-virus, any open file handles, and the moon phase.
electron-store
is usingwrite-file-atomic
, which uses the plain Node.jsfs
api. I think for this to be improved,write-file-atomic
need to instead usefs-extra
(which handles the EXDEV issue #106) and it usesgraceful-fs
which handles the EPERM issue with a 1 second retry loop.One problem is that even with
graceful-fs
there are still issues with EPERM on windows even though it has 1 second retry logicAnd I don’t think the
write-file-atomic
guys want to use introduce two extra layers of abstraction by addingfs-extra
dependency, becausewrite-file-atomic
is being used by a lot of packages includingnpm
and it might introduce regressions for a lot of people.So I think either electron-store needs to either:
platform.os === 'win32'
)EPERM
to the catch block if-check along withEXDEV
to retry with fs.writeFileSync. I’m not sure if this will work because EPERM seems to be caused by the target file being occupied by antivirus or something else for some time, and I’m not sure if writeFileSync will also throw EPERM if the file is still occupiedfs-extra
which better handles these errors.electron-store
README about the fact that theset
andnew Store()
functions is likely to fail often on Windows and that they need to handle this in their code with try/catch around these functionsReleased: https://github.com/sindresorhus/electron-store/releases/tag/v6.0.0
Yes, you can replace it as-is. But only thing changed is the timeout (from 100ms to 500ms) that is given to the operating system for finishing the write operation. In other words, we allow the operating system more time to do the write operation before aborting.
@bad2Dbone It sounds like you are using a version with
atomically
already, in that case there isn’t too much that can be done, like there are no guarantees that write operations will always succeed, especially in hostile environments like Windows with an aggressive antivirus, you might want to consider switching to asynchronous writes rather than synchronous, as the former have a higher default timeout, or you could just provideatomically
a higher up timeout is that sounds like a good trade off to you, although currently I don’t thinkconf
andelectron-store
allow you to change these things 🤔@jurepetrovic There are all sorts of factors that have an impact on this, including if the sun is shining outside or not, and we can’t really do much about them, maybe in your case just having all files packages in an
asar
archive makes the antivirus take longer to scan it and unlock it, even if the part of the archive being scanned is not the one you currently care about. But I don’t think you are writing into theasar
so probably that doesn’t matter 🤔https://www.npmjs.com/package/electron-store-atomically
If we merge this successfully and it works under windows, I’d be very happy to use this original package!
I have made PR #130 , but it requires some more testing for real production. Actually the real change is in conf-atomically, where the atomically is actually used.
I had to change some project data, since I published separate npm package on npmjs for our own use.
Thanks and Rgds, Jure
I’ve once again read the doc of this proj, and this time I found something may be good for you (and for me, too). Haven’t tested myself, though I’m thinking that by using this, your code may need to be complex.
Anyway, I think for using this lib, try-catches are necessary (and it also seems to be the most convenient and least costly solution to partially fix this?) to make your code stronger…