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)

Most upvoted comments

I welcome a fork that’s better maintained.

@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 say atomically is probably strictly better than write-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 from write-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 using write-file-atomic, which uses the plain Node.js fs api. I think for this to be improved, write-file-atomic need to instead use fs-extra (which handles the EXDEV issue #106) and it uses graceful-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 logic

And I don’t think the write-file-atomic guys want to use introduce two extra layers of abstraction by adding fs-extra dependency, because write-file-atomic is being used by a lot of packages including npm and it might introduce regressions for a lot of people.

So I think either electron-store needs to either:

  1. Change the code that uses write-file-sync to instead write the file directly with no atomicity guarantee. (or only do so if platform.os === 'win32')
  2. include EPERM to the catch block if-check along with EXDEV 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 occupied
  3. Write our own write-file-atomic implementation replacement that does the same but instead uses fs-extra which better handles these errors.
  4. Find another way to guarantee atomicity when writing a config file
  5. Keep it as is, but give the developers huge warnings in the electron-store README about the fact that the set and new Store() functions is likely to fail often on Windows and that they need to handle this in their code with try/catch around these functions

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 provide atomically a higher up timeout is that sounds like a good trade off to you, although currently I don’t think conf and electron-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 the asar 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

image

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…