Skip to content

fix: do not throw when fs is not extensible - #263

Closed
dyk1454683243-sudo wants to merge 2 commits into
isaacs:mainfrom
dyk1454683243-sudo:cursor/fix-non-extensible-fs-queue-8175
Closed

dyk1454683243-sudo wants to merge 2 commits into
isaacs:mainfrom
dyk1454683243-sudo:cursor/fix-non-extensible-fs-queue-8175

Conversation

@dyk1454683243-sudo

@dyk1454683243-sudo dyk1454683243-sudo commented Sep 20, 2026

Copy link
Copy Markdown

Fixes #245

Bug

In ESM, import * as fs from 'node:fs' is a non-extensible namespace object. graceful-fs published the shared retry queue with Object.defineProperty(fs, Symbol.for('graceful-fs.queue'), …) and threw:

TypeError: Cannot define property Symbol(graceful-fs.queue), object is not extensible

Reproduced on current main by Object.preventExtensions(require('fs')) then require('graceful-fs').

Fix

  • If fs (or global) is not extensible, skip defining the queue Symbol on that object instead of throwing.
  • Keep the existing Symbol-on-fs publish path when Object.isExtensible(fs) is true, so CJS / multi-copy queue sharing is unchanged.
  • When the Symbol cannot be stored on fs, use global[Symbol.for('graceful-fs.queue')] (already used for cross-version sharing) and a module-local array as fallbacks.
  • Queue reads (enqueue / retry / resetQueue) go through getQueue() so the fallback is used.

This is a separate change from #262 (getter-only fs.close).

Tests

  • test/non-extensible-fs.js: load this tree against a cloned, Object.preventExtensions fs-like object (nyc preloads node_modules/graceful-fs onto the real fs). Asserts load does not throw, file ops still work, the queue is not defined on the non-extensible object, later loads share the global queue, and EMFILE retries still drain that queue.
  • test/queue-published-on-fs.js: extensible CJS fs still gets the Symbol and shares one array with global.

Local npm test: 49472 passing.

Claim-check

cursoragent and others added 2 commits September 20, 2026 21:14
Store the shared retry queue off the fs object when it is not
extensible (ESM node:fs namespace), while keeping the existing
Symbol-on-fs publish path when Object.isExtensible(fs) is true.

Fixes isaacs#245

Co-authored-by: David <dyk1454683243-sudo@users.noreply.github.com>
nyc loads node_modules/graceful-fs before tests, which already
publishes the queue Symbol on the real fs. Load this tree against
a cloned, Object.preventExtensions fs-like object instead.

Co-authored-by: David <dyk1454683243-sudo@users.noreply.github.com>
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.

TypeError: Cannot define property Symbol(graceful-fs.queue), object is not extensible

3 participants