Skip to content

core: fs.openSync in fingerprint.js fails with EINVAL on Windows under Node.js >= 26.8.0 (O_SYNC | O_DSYNC combination) #38692

Closed

Description

@soberm

Describe the bug

On Windows, asset fingerprinting throws EINVAL: invalid argument, open for every file it hashes when running on Node.js 26.8.0 or newer. The failure originates in aws-cdk-lib/core/lib/fs/fingerprint.js, in contentFingerprintMiss(), which opens files with the flag combination fs.constants.O_DSYNC | fs.constants.O_RDONLY | fs.constants.O_SYNC.

Before Node.js 26.8.0, O_SYNC and O_DSYNC were undefined on Windows, so this expression coerced to 0 (effectively O_RDONLY) and the open succeeded. Node.js 26.8.0 (nodejs/node#64707) defined these constants on Windows as real, non-zero bits. The unchanged CDK line now passes both O_SYNC and O_DSYNC set simultaneously to fs.openSync. libuv's Windows fs__open() explicitly rejects that combination and returns UV_EINVAL / Win32 ERROR_INVALID_PARAMETER.

This breaks CDK synth / asset staging on Windows with Node.js >= 26.8.0.

Regression Issue

  • Select this option if this issue appears to be a regression.

This is a regression triggered by the Node.js runtime version (26.7.0 works, 26.8.0/26.8.1 fail on the identical aws-cdk-lib code).

Last Known Working CDK Library Version

aws-cdk-lib 2.244.0 works on Node.js <= 26.7.0. The aws-cdk-lib code is unchanged across the break — the regression is gated purely on the Node.js runtime version.

Expected Behavior

Asset fingerprinting / synth should open files for read-hashing successfully on Windows regardless of Node.js patch version. A read-only content hash has no need for O_SYNC/O_DSYNC (write-through) semantics, so the open should not fail with EINVAL.

Current Behavior

On Windows + Node.js >= 26.8.0, every file hashed during asset staging throws:

Error: EINVAL: invalid argument, open 'D:\...\index.js'
    at Object.openSync (node:fs:779:18)
    at contentFingerprintMiss (node_modules/aws-cdk-lib/core/lib/fs/fingerprint.js)
    at contentFingerprint (node_modules/aws-cdk-lib/core/lib/fs/fingerprint.js)
    at _processFileOrDirectory (node_modules/aws-cdk-lib/core/lib/fs/fingerprint.js)
    at FileSystem.fingerprint (node_modules/aws-cdk-lib/core/lib/fs/index.js)
    at AssetStaging.calculateHash (node_modules/aws-cdk-lib/core/lib/asset-staging.js)
  { errno: -4071, code: 'EINVAL', syscall: 'open', path: '...' }

The offending call in fingerprint.js contentFingerprintMiss():

const fd = fs.openSync(file, fs.constants.O_DSYNC | fs.constants.O_RDONLY | fs.constants.O_SYNC);

Reproduction Steps

On a Windows machine with Node.js >= 26.8.0, this self-contained snippet reproduces the exact failure against the same code path:

// repro.js — run with `node repro.js` on Windows under Node >= 26.8.0
const fs = require('fs');
const os = require('os');
const path = require('path');

const file = path.join(os.tmpdir(), 'cdk-einval-repro.txt');
fs.writeFileSync(file, 'hello');

// Exactly what aws-cdk-lib/core/lib/fs/fingerprint.js contentFingerprintMiss() does:
const flags = fs.constants.O_DSYNC | fs.constants.O_RDONLY | fs.constants.O_SYNC;
const fd = fs.openSync(file, flags); // throws EINVAL on Windows + Node >= 26.8.0
fs.closeSync(fd);
console.log('opened OK');

Alternatively, cdk synth of any stack containing a Lambda/asset on Windows + Node.js 26.8.0 triggers it via AssetStaging.calculateHash.

Possible Solution

In core/lib/fs/fingerprint.js contentFingerprintMiss(), drop the O_SYNC/O_DSYNC flags — they request write-through/sync semantics that are meaningless for a read-only hash — and open read-only:

// before
const fd = fs.openSync(file, fs.constants.O_DSYNC | fs.constants.O_RDONLY | fs.constants.O_SYNC);
// after
const fd = fs.openSync(file, fs.constants.O_RDONLY);

This is platform-agnostic and removes flags that never served a purpose for hashing. (Separately, libuv/Node arguably should treat O_SYNC+O_DSYNC as idempotent on Windows like POSIX; a companion nodejs/node issue against #64707 may be warranted, but the CDK-side change fully resolves the user-facing break.)

Additional Information/Context

Verified root-cause chain:

  1. Node.js <= 26.7.0: fs.constants.O_SYNC/O_DSYNC are undefined on Windows → undefined | 0 | undefined coerces to 0 → benign O_RDONLY open. Works.
  2. src: define O_SYNC, O_DSYNC and O_DIRECT on Windows nodejs/node#64707 ("src: define O_SYNC, O_DSYNC and O_DIRECT on Windows", shipped in v26.8.0) defines them on Windows as real bits: O_SYNC=0x08000000, O_DSYNC=0x04000000.
  3. CDK's unchanged line now computes flags = 0x0C000000 (both sync bits set) and passes them to fs.openSync.
  4. libuv Windows fs__open() (src/win/fs.c): switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) handles 0 / O_DSYNC-alone / O_SYNC-alone, but BOTH bits set falls through to default: goto einval; → UV_EINVAL / ERROR_INVALID_PARAMETER.
  5. Surfaces as EINVAL … errno -4071 … syscall 'open'.
  6. POSIX kernels treat both-sync-bits as harmless, so Linux/macOS are unaffected.

AWS CDK Library version (aws-cdk-lib)

2.244.0

AWS CDK CLI version

2.1113.0

Node.js Version

Fails on 26.8.0 and 26.8.1; last known working 26.7.0

OS

Windows (GitHub Actions windows-2025 runner; expected on Windows generally)

Language

TypeScript

Other information

Suspected trigger: nodejs/node#64707 (companion #64775 exposes further Windows fs flags). aws-cdk-lib is unchanged across the regression — the break is gated purely on the Node.js runtime version.

Activity

  1. added
    needs-triageThis issue or PR still needs to be triaged.
    potential-regressionMarking this issue as a potential regression to be checked by team member
    @aws-cdk/coreRelated to core CDK functionality
    on Aug 28, 2026
  2. added
    investigatingThis issue is being investigated and/or work is in progress to resolve the issue.
    on Aug 28, 2026
  3. pahud commented on Aug 28, 2026

    @pahud
    Contributor

    Hi @soberm,

    ┌──────────────────────────────────────────────────────────────┐
    │ 🔴 Reported State                                           │
    │ CDK 2.244.0 asset hashing fails on Windows with Node 26.8    │
    └──────────────────────────────┬───────────────────────────────┘
                                   │
                                   ▼
    ┌──────────────────────────────────────────────────────────────┐
    │ 🔍 Root Cause                                                │
    │ Both O_SYNC and O_DSYNC are passed to Windows libuv          │
    └──────────────────────────────┬───────────────────────────────┘
                                   │
                                   ▼
    ┌──────────────────────────────────────────────────────────────┐
    │ 🟢 Suggested Fix                                             │
    │ Upgrade aws-cdk-lib to 2.254.0 or newer                      │
    └──────────────────────────────────────────────────────────────┘
    

    This is a good catch, and the root-cause analysis matches the affected 2.244.0 artifact. I wasn't able to reproduce the Windows-only EINVAL locally because my available environment is macOS; the exact snippet opens successfully there, as expected. I did verify that published 2.244.0 passes both sync flags and that Windows libuv rejects that combination once Node.js exposes them.

    The good news is that this was already fixed by #37802 before Node.js 26.8.0 was released. contentFingerprintMiss() now opens files with O_RDONLY only, and the change first shipped in [email protected]:

    function contentFingerprintMiss(file: string): string {
    const hash = crypto.createHash('sha256');
    const buffer = Buffer.alloc(BUFFER_SIZE);
    const fd = fs.openSync(file, fs.constants.O_RDONLY);
    let size = 0;

    https://github.com/aws/aws-cdk/releases/tag/v2.254.0

    Could you try upgrading aws-cdk-lib to 2.254.0 or newer? The current latest release, 2.267.0, also contains this fix. If it still reproduces after upgrading, please share the resolved aws-cdk-lib version and updated stack trace and we can investigate further.

    Since the implementation is already fixed, no additional code change appears necessary. If you'd like to contribute, a focused regression test asserting that fingerprinting passes only O_RDONLY to fs.openSync() would still be welcome.

  4. added
    response-requestedWaiting on additional info and feedback. Will move to "closing-soon" in 7 days.
    effort/smallSmall work item – less than a day of effort
    and removed
    investigatingThis issue is being investigated and/or work is in progress to resolve the issue.
    needs-triageThis issue or PR still needs to be triaged.
    potential-regressionMarking this issue as a potential regression to be checked by team member
    on Aug 28, 2026
  5. github-actions commented on Aug 30, 2026

    @github-actions
    Contributor

    This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.

  6. added
    closing-soonThis issue will automatically close in 4 days unless further comments are made.
    on Aug 30, 2026
  7. added
    closed-for-stalenessThis issue was automatically closed because it hadn't received any attention in a while.
    and removed
    closing-soonThis issue will automatically close in 4 days unless further comments are made.
    on Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    @aws-cdk/coreRelated to core CDK functionalityclosed-for-stalenessThis issue was automatically closed because it hadn't received any attention in a while.effort/smallSmall work item – less than a day of effortp3response-requestedWaiting on additional info and feedback. Will move to "closing-soon" in 7 days.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions