Skip to content

fix(state): avoid temp-file race in atomic_write_file with multiple monitors - #1813

Merged
eythaann merged 2 commits into
eythaann:masterfrom
z1pp090:fix/atomic-write-race
Sep 15, 2026
Merged

eythaann merged 2 commits into
eythaann:masterfrom
z1pp090:fix/atomic-write-race

Conversation

@z1pp090

@z1pp090 z1pp090 commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

Problem

With more than one monitor there is one dock (and one toolbar) webview per monitor, and each of them saves its state through StateWriteWegItems / StateWriteToolbarItems at the same moment. Both calls end up in atomic_write_file using the same temporary file (state.yml.tmp): the first rename moves it into place and the second one fails with

[ERROR][@seelen/weg?monitorId=...]  Unhandled Rejection Io(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." })

right after Saving dock state in Seelen UI.log. Nothing is lost, because both writers carry the same content, but the error fires on every save with two monitors (on my machine: every few seconds after a layout change, and on every startup).

Fix

  • atomic_write_file now uses a temporary name that is unique per call (<name>.<pid>.<counter>.tmp), and removes it if the rename fails.
  • WegItemsManager::write and ToolbarItemsManager::write hold the manager lock while writing, so in-process saves are serialized instead of racing on the same target.

Three files, no new dependencies.

Verification

I do not have a Rust toolchain on this machine, so the change has only been verified by CI (fmt, clippy, tests) on a PR against my own fork: z1pp090#2. I have not run the resulting build. The diagnosis comes from the log correlation on a two-monitor Windows 11 25H2 setup (2.8.4): the NotFound error appears only when both monitors log Saving dock state in the same second, and always on the second one.

πŸ€– Generated with Claude Code

z1pp090 and others added 2 commits September 13, 2026 17:13
With more than one monitor there is one dock (and one toolbar) webview per
monitor, and each of them saves its state through `StateWriteWegItems` /
`StateWriteToolbarItems` at the same moment. Both calls ended up in
`atomic_write_file` using the same `state.yml.tmp`: the first rename moved
the file into place and the second one failed with

    Unhandled Rejection Io(Os { code: 2, kind: NotFound, ... })

right after "Saving dock state" in the log. Nothing was lost (both writers
carried the same content) but the error fired on every save with two
monitors.

- Give every `atomic_write_file` call its own temporary file name
  (`<name>.<pid>.<counter>.tmp`) and remove it if the rename fails.
- Hold the manager lock while writing in `WegItemsManager::write` and
  `ToolbarItemsManager::write`, so in-process saves are serialized instead
  of racing on the same target.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StkifHpSLWH4J5TvuP56ur
@eythaann
eythaann self-requested a review September 15, 2026 14:41
@eythaann
eythaann merged commit ab9db2f into eythaann:master Sep 15, 2026
4 checks passed
@z1pp090
z1pp090 deleted the fix/atomic-write-race branch September 24, 2026 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants