or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-graceful-fs

A drop-in replacement for fs, making various improvements.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/graceful-fs@4.2.x

To install, run

npx @tessl/cli install tessl/npm-graceful-fs@4.2.0

index.mddocs/

Graceful FS

Graceful FS is a drop-in replacement for Node.js's built-in fs module that makes filesystem operations more resilient to errors and cross-platform inconsistencies. It implements intelligent retry mechanisms for EMFILE errors, handles platform-specific quirks like Windows antivirus interference, and provides fallbacks for missing filesystem operations.

Package Information

  • Package Name: graceful-fs
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install graceful-fs

Core Imports

const fs = require('graceful-fs');

For global patching (use with caution):

const fs = require('fs');
const gracefulFs = require('graceful-fs');
gracefulFs.gracefulify(fs);

Basic Usage

const fs = require('graceful-fs');

// All standard fs operations work as normal, but with enhanced error handling
fs.readFile('package.json', 'utf8', (err, data) => {
  if (err) {
    console.error('Error reading file:', err);
    return;
  }
  console.log('File contents:', data);
});

// File operations are automatically retried on EMFILE/ENFILE errors
fs.writeFile('output.txt', 'Hello World', (err) => {
  if (err) {
    console.error('Error writing file:', err);
    return;
  }
  console.log('File written successfully');
});

Architecture

Graceful FS enhances the standard Node.js fs module with:

  • Retry Queue System: Automatically queues and retries operations when file descriptor limits are reached (EMFILE/ENFILE errors)
  • Cross-platform Polyfills: Provides fallback implementations for missing filesystem operations on different platforms
  • Error Tolerance: Gracefully handles permission errors for non-root users and platform-specific limitations
  • Stream Enhancements: Enhanced ReadStream and WriteStream classes with improved error handling
  • Global Patching: Ability to patch the global fs module to apply enhancements system-wide

Capabilities

Enhanced File Operations

All standard Node.js fs methods are available with enhanced error handling and retry logic. Operations are automatically retried on transient errors and queued when file descriptor limits are reached.

/**
 * Read entire file contents with EMFILE/ENFILE retry
 * @param path - File path (string|Buffer|URL|number)
 * @param options - Encoding or options object {encoding, flag}
 * @param callback - (err, data) => void
 */
function readFile(path, options, callback);
function readFileSync(path, options);

/**
 * Write data to file with EMFILE/ENFILE retry
 * @param path - File path (string|Buffer|URL|number)
 * @param data - Data to write (string|Buffer|TypedArray|DataView)
 * @param options - Encoding or options object {encoding, mode, flag}
 * @param callback - (err) => void
 */
function writeFile(path, data, options, callback);
function writeFileSync(path, data, options);

/**
 * Append data to file with EMFILE/ENFILE retry
 * @param path - File path (string|Buffer|URL|number)
 * @param data - Data to append (string|Buffer)
 * @param options - Encoding or options object {encoding, mode, flag}
 * @param callback - (err) => void
 */
function appendFile(path, data, options, callback);
function appendFileSync(path, data, options);

/**
 * Copy file with EMFILE/ENFILE retry
 * @param src - Source file path (string|Buffer|URL)
 * @param dest - Destination file path (string|Buffer|URL)
 * @param flags - Copy flags (number, optional)
 * @param callback - (err) => void
 */
function copyFile(src, dest, flags, callback);
function copyFileSync(src, dest, flags);

/**
 * Open file with EMFILE/ENFILE retry and queue management
 * @param path - File path (string|Buffer|URL)
 * @param flags - File open flags (string|number)
 * @param mode - File mode (integer, optional)
 * @param callback - (err, fd) => void
 */
function open(path, flags, mode, callback);
function openSync(path, flags, mode);

/**
 * Close file descriptor with queue management and retry processing
 * @param fd - File descriptor (integer)
 * @param callback - (err) => void
 */
function close(fd, callback);
function closeSync(fd);

/**
 * Read from file descriptor with EAGAIN retry (up to 10 attempts)
 * @param fd - File descriptor (integer)
 * @param buffer - Buffer to read into
 * @param offset - Buffer offset to start writing at
 * @param length - Number of bytes to read
 * @param position - File position to read from (null for current position)
 * @param callback - (err, bytesRead, buffer) => void
 */
function read(fd, buffer, offset, length, position, callback);
function readSync(fd, buffer, offset, length, position);

/**
 * Rename file with Windows antivirus retry logic (up to 60s on Windows)
 * @param from - Current file path (string|Buffer|URL)
 * @param to - New file path (string|Buffer|URL)
 * @param callback - (err) => void
 */
function rename(from, to, callback);
function renameSync(from, to);

Enhanced Directory Operations

Directory operations with improved error handling and consistent behavior across platforms.

/**
 * Read directory contents with EMFILE/ENFILE retry and automatic sorting
 * @param path - Directory path (string|Buffer|URL)
 * @param options - Encoding or options object {encoding, withFileTypes}
 * @param callback - (err, files) => void where files are automatically sorted
 */
function readdir(path, options, callback);
function readdirSync(path, options);

Enhanced File Streams

Enhanced stream classes with improved error handling and retry logic.

/**
 * Enhanced readable file stream with EMFILE/ENFILE retry logic
 * @extends require('stream').Readable
 */
class ReadStream extends require('stream').Readable {
  /**
   * @param path - File path (string|Buffer|URL)
   * @param options - Stream options {flags, encoding, fd, mode, autoClose, emitClose, start, end, highWaterMark}
   */
  constructor(path, options);
  
  /** Enhanced open method with retry logic */
  open();
}

/**
 * Enhanced writable file stream with EMFILE/ENFILE retry logic
 * @extends require('stream').Writable
 */
class WriteStream extends require('stream').Writable {
  /**
   * @param path - File path (string|Buffer|URL)
   * @param options - Stream options {flags, encoding, fd, mode, autoClose, emitClose, start, highWaterMark}
   */
  constructor(path, options);
  
  /** Enhanced open method with retry logic */
  open();
}

/**
 * Create enhanced readable stream with retry logic
 * @param path - File path (string|Buffer|URL)
 * @param options - Stream options object
 * @returns ReadStream instance
 */
function createReadStream(path, options);

/**
 * Create enhanced writable stream with retry logic
 * @param path - File path (string|Buffer|URL)
 * @param options - Stream options object
 * @returns WriteStream instance
 */
function createWriteStream(path, options);

/**
 * Legacy alias for ReadStream (for compatibility)
 */
class FileReadStream extends ReadStream {}

/**
 * Legacy alias for WriteStream (for compatibility)
 */
class FileWriteStream extends WriteStream {}

File Permissions and Ownership

File permission and ownership operations with enhanced error tolerance for non-root users. These methods gracefully ignore EINVAL, EPERM errors when not running as root, and ENOSYS errors on filesystems that don't support the operation.

/**
 * Change file ownership, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
 * @param path - File path (string|Buffer|URL)
 * @param uid - User ID (integer)
 * @param gid - Group ID (integer)
 * @param callback - (err) => void
 */
function chown(path, uid, gid, callback);
function chownSync(path, uid, gid);

/**
 * Change file ownership by descriptor, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
 * @param fd - File descriptor (integer)
 * @param uid - User ID (integer)
 * @param gid - Group ID (integer)
 * @param callback - (err) => void
 */
function fchown(fd, uid, gid, callback);
function fchownSync(fd, uid, gid);

/**
 * Change symlink ownership, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
 * @param path - Symlink path (string|Buffer|URL)
 * @param uid - User ID (integer)
 * @param gid - Group ID (integer)
 * @param callback - (err) => void
 */
function lchown(path, uid, gid, callback);
function lchownSync(path, uid, gid);

/**
 * Change file permissions, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
 * @param path - File path (string|Buffer|URL)
 * @param mode - Permission mode (integer)
 * @param callback - (err) => void
 */
function chmod(path, mode, callback);
function chmodSync(path, mode);

/**
 * Change file permissions by descriptor, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
 * @param fd - File descriptor (integer)
 * @param mode - Permission mode (integer)
 * @param callback - (err) => void
 */
function fchmod(fd, mode, callback);
function fchmodSync(fd, mode);

/**
 * Change symlink permissions (polyfilled or noop if unavailable)
 * @param path - Symlink path (string|Buffer|URL)
 * @param mode - Permission mode (integer)
 * @param callback - (err) => void
 */
function lchmod(path, mode, callback);
function lchmodSync(path, mode);

File Stats and Information

File stat operations with fixes for platform-specific issues like negative uid/gid values, converting them to proper unsigned 32-bit integers.

/**
 * Get file statistics, fixes negative uid/gid values on older Node.js versions
 * @param path - File path (string|Buffer|URL)
 * @param options - Options object {bigint: boolean} (optional)
 * @param callback - (err, stats) => void
 */
function stat(path, options, callback);
function statSync(path, options);

/**
 * Get file statistics by descriptor, fixes negative uid/gid values
 * @param fd - File descriptor (integer)
 * @param options - Options object {bigint: boolean} (optional)
 * @param callback - (err, stats) => void
 */
function fstat(fd, options, callback);
function fstatSync(fd, options);

/**
 * Get symlink statistics without following, fixes negative uid/gid values
 * @param path - Symlink path (string|Buffer|URL)
 * @param options - Options object {bigint: boolean} (optional)
 * @param callback - (err, stats) => void
 */
function lstat(path, options, callback);
function lstatSync(path, options);

File Times

File timestamp operations with polyfills for missing platform functionality.

/**
 * Change file access and modification times
 * @param path - File path (string|Buffer|URL)
 * @param atime - Access time (Date|number)
 * @param mtime - Modification time (Date|number)
 * @param callback - (err) => void
 */
function utimes(path, atime, mtime, callback);
function utimesSync(path, atime, mtime);

/**
 * Change file times by descriptor
 * @param fd - File descriptor (integer)
 * @param atime - Access time (Date|number)
 * @param mtime - Modification time (Date|number)
 * @param callback - (err) => void
 */
function futimes(fd, atime, mtime, callback);
function futimesSync(fd, atime, mtime);

/**
 * Change symlink times (polyfilled using futimes on opened symlink)
 * @param path - Symlink path (string|Buffer|URL)
 * @param atime - Access time (Date|number)
 * @param mtime - Modification time (Date|number)
 * @param callback - (err) => void
 */
function lutimes(path, atime, mtime, callback);
function lutimesSync(path, atime, mtime);

Global Patching

Apply graceful-fs enhancements to any fs-like module.

/**
 * Apply graceful-fs patches to any fs-like module or object
 * @param fs - The fs module or fs-like object to patch
 * @returns The patched fs object with graceful-fs enhancements
 */
function gracefulify(fs);

Usage Example:

const fs = require('fs');
const gracefulFs = require('graceful-fs');

// Patch the global fs module
gracefulFs.gracefulify(fs);

// Now all fs operations use graceful-fs enhancements
fs.readFile('file.txt', callback);

Process Enhancements

Enhanced process methods for better working directory handling.

/**
 * Enhanced process.cwd with caching for better performance
 * @returns string - Current working directory path
 */
process.cwd();

/**
 * Enhanced process.chdir that clears cwd cache
 * @param directory - Directory path to change to
 */
process.chdir(directory);

Internal Queue Access

Read-only access to the internal retry queue for debugging and monitoring.

/**
 * Access to internal retry queue (read-only)
 * @readonly
 */
fs[Symbol.for('graceful-fs.queue')];

Error Handling

Graceful FS automatically handles several types of filesystem errors with sophisticated retry and tolerance mechanisms:

Retry Logic Details

  • EMFILE/ENFILE Errors: File descriptor limit errors are automatically queued and retried

    • Maximum retry time: 60 seconds total
    • Backoff strategy: Exponential backoff starting at 1ms, increasing by 1.2x each attempt, capped at 100ms
    • Queue management: Global queue shared across all graceful-fs instances
    • Applies to: open(), readFile(), writeFile(), appendFile(), copyFile(), readdir()
  • EAGAIN Errors: Temporary resource unavailable errors in read operations

    • Maximum retries: Up to 10 attempts
    • Applies to: read() and readSync() operations
  • Windows Rename Retry Logic: Special handling for antivirus software interference

    • Target errors: EACCES, EPERM, EBUSY on Windows only
    • Retry duration: Up to 60 seconds with exponential backoff
    • Applies to: rename() operations on Windows

Error Tolerance

  • EINVAL/EPERM: Permission errors in ownership/permission operations are gracefully ignored for non-root users

    • Applies to: All chown(), fchown(), lchown(), chmod(), fchmod(), lchmod() operations
    • Rationale: Non-root users often cannot change ownership, this shouldn't break applications
  • ENOSYS: Errors indicating filesystem doesn't support an operation are ignored

    • Applies to: All permission and ownership operations
    • Rationale: Some filesystems don't support these operations, applications should continue

Platform-Specific Fixes

  • Negative UID/GID: On older Node.js versions, converts negative values to proper unsigned 32-bit integers
  • Windows Compatibility: Enhanced retry logic specifically for Windows antivirus interference
  • Node.js Version Differences: Handles API differences across Node.js versions automatically

All enhanced methods maintain the same API as the standard Node.js fs module, making graceful-fs a true drop-in replacement.

Complete fs Compatibility

In addition to the enhanced methods documented above, graceful-fs provides access to ALL standard Node.js fs methods with the same signatures and behavior. Methods not explicitly enhanced by graceful-fs are passed through unchanged, ensuring complete compatibility with existing code. This includes methods like:

  • access(), accessSync()
  • exists(), existsSync()
  • mkdir(), mkdirSync()
  • rmdir(), rmdirSync()
  • unlink(), unlinkSync()
  • symlink(), symlinkSync()
  • readlink(), readlinkSync()
  • truncate(), truncateSync()
  • ftruncate(), ftruncateSync()
  • watch(), watchFile(), unwatchFile()
  • realpath(), realpathSync()
  • mkdtemp(), mkdtempSync()
  • And all other Node.js fs methods

All methods retain their original signatures, callback patterns, and error handling, with graceful-fs enhancements applied only where beneficial for reliability and cross-platform compatibility.