#623·evolver

[Windows] fdatasyncSync on read-only fd throws EPERM, blocks node credential snapshot (canonicalIdentityLock.js)

Author: tree1961Created Sep 5, 2026Updated Sep 5, 2026

Summary

On Windows, src/canonicalIdentityLock.js opens the owner file in read-only mode and then calls fs.fdatasyncSync() on that descriptor. Windows' fdatasync (backed by FlushFileBuffers) requires a writable handle, so a read-only fd throws EPERM: operation not permitted, fdatasync. This breaks the canonical node-credential snapshot, so node registration / hello handshake cannot persist credentials.

Steps to reproduce

  1. On Windows, clone and npm install.
  2. Run node index.js (or --loop).
  3. Observe the non-fatal errors:
[a2aProtocol] Failed to snapshot canonical node credentials: EPERM
[TaskReceiver] Fetch/claim failed (non-fatal): EPERM: operation not permitted, fdatasync

Minimal repro:

javascript
const fs = require('fs');
fs.writeFileSync('x', 'hello');
const fd = fs.openSync('x', 'r'); // read-only
fs.fdatasyncSync(fd);             // throws EPERM on Windows

Root cause

src/canonicalIdentityLock.js, prepareOwnerFile():

javascript
descriptor = fs.openSync(preparedOwnerFile, 'r'); // read-only
fs.fdatasyncSync(descriptor);                      // EPERM on win32

fdatasync on a read-only fd is tolerated on Linux/macOS but fails on Windows (FlushFileBuffers -> ERROR_ACCESS_DENIED -> EPERM).

Suggested fix

Open read+write so fdatasync has a writable handle:

javascript
descriptor = fs.openSync(preparedOwnerFile, 'r+');
fs.fdatasyncSync(descriptor);

Environment

  • OS: Windows (win32)
  • Node.js: v22.22.2
  • Evolver version: 1.94.0