Skip to content

Errors thrown by node:fs callbacks and node:fs/promises: util.types.isNativeError() returns false #2152

Description

@karlhorky

Companion StackBlitz issue to pnpm issue pnpm/pnpm#14030

Describe the bug

On StackBlitz WebContainers, errors from:

  1. callback-based node:fs APIs
  2. node:fs/promises

...cause util.types.isNativeError() to report false.

The errors have the expected properties such as code: 'ENOENT', but util.types.isNativeError(error) returns false. Equivalent errors from synchronous node:fs APIs return true (also tested to return true: node:child_process, node:crypto, node:zlib).

This causes unexpected errors in software like pnpm 10 - which uses util.types.isNativeError() when handling filesystem errors.

Link to the blitz that caused the error

https://stackblitz.com/github/stackblitz/starters/tree/main/node?file=index.js

Steps to reproduce

  1. Visit the reproduction URL above
  2. Compare synchronous node:fs, node:fs/promises, and callback-based node:fs errors, and observe util.types.isNativeError() returning false for the asynchronous APIs 💥
    ~/projects/qgnivomaqj.github
    ❯ node --input-type=module --eval "
    import fs from 'node:fs';
    import fsPromises from 'node:fs/promises';
    import util from 'node:util';
    
    try {
      fs.readFileSync('/does-not-exist');
    } catch (error) {
      console.log('node:fs fs.readFileSync()', {
        code: error.code,
        constructor: error.constructor.name,
        isNativeError: util.types.isNativeError(error),
      });
    }
    
    try {
      await fsPromises.readFile('/does-not-exist');
    } catch (error) {
      console.log('node:fs/promises fsPromises.readFile()', {
        code: error.code,
        constructor: error.constructor.name,
        isNativeError: util.types.isNativeError(error),
      });
    }
    
    fs.readFile('/does-not-exist', error => {
      console.log('node:fs fs.readFile() callback', {
        code: error.code,
        constructor: error.constructor.name,
        isNativeError: util.types.isNativeError(error),
      });
    });
    "
    node:fs fs.readFileSync() { code: 'ENOENT', constructor: 'Error', isNativeError: true }
    node:fs/promises fsPromises.readFile() { code: 'ENOENT', constructor: 'Error', isNativeError: false }
    node:fs fs.readFile() callback { code: 'ENOENT', constructor: 'Error', isNativeError: false }

Expected behavior

Errors from all Node.js APIs (incl. callback-based node:fs APIs and node:fs/promises) are recognized by util.types.isNativeError(), like equivalent synchronous node:fs errors.

Parity with Local

Screenshots

No response

Platform

  • OS: macOS Tahoe 26.5.2 (25F84)
  • Browser: Chrome
  • Version: 151.0.7922.138 (macOS)

Additional context

This causes pnpm 10 to re-throw ENOENT errors for *optional* config files:

cc @SamVerschueren if this should be reported some other way or in stackblitz/core, let me know

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions