Skip to content

fix: guard against require.cache being unavailable - #122

Open
GiHoon1123 wants to merge 1 commit into
nodejs:mainfrom
GiHoon1123:fix-113-require-cache-undefined
Open

fix: guard against require.cache being unavailable#122
GiHoon1123 wants to merge 1 commit into
nodejs:mainfrom
GiHoon1123:fix-113-require-cache-undefined

Conversation

@GiHoon1123

@GiHoon1123 GiHoon1123 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

ExportsCache's has()/get()/set() methods assume require.cache always exists as an object. When this package is bundled by a tool like esbuild for an ESM target, the bundler substitutes its own require shim (no .cache property) for the real Node.js require. Indexing into require.cache then throws Cannot read properties of undefined (reading '...'), instead of falling back to the internal Map the class already uses when a module is missing from require.cache.

Fix

Add a require.cache truthiness check alongside the existing isBuiltin check in has(), get(), and set(). Falls back to the internal Map when require.cache itself is missing, not just when an entry is missing from it. No change in normal Node.js environments, where require.cache is always present.

Known limitation, not introduced by this fix: when require.cache is unavailable, non-core modules are cached in the internal Map instead. The existing delete require.cache[...]-to-force-a-reload trick (see test/require-cache-inval.js) doesn't work in that environment, since the internal Map has no external invalidation hook.

Test

Added test/require-cache-undefined.test.js. Uses vm + Module.wrap() to load index.js's own source with a require shim that has no .cache property, matching esbuild's shim shape - no need to add esbuild as a dependency.

  • Test reproduces the crash on unmodified index.js.
  • Passes with the fix.
  • Full suite (npm test: lint + 102 tape tests + babel test) passes.

Relationship to #121

#121 addresses #120 (webpack replacing require.resolve, a broader external-module-resolution problem). This PR is a narrower, independent fix for the require.cache === undefined crash in #113 - no overlap in scope.

Test plan

  • Added regression test reproducing the exact crash
  • Confirmed regression test fails without the fix
  • Full local suite (lint + tape + babel) passes

Fixes #113

ExportsCache's has()/get()/set() assumed `require.cache` always
exists. When this package is bundled by a tool like esbuild for an
ESM target, the bundler substitutes its own `require` shim (without
a `.cache` property) for the real Node.js `require`, so indexing into
`require.cache` throws instead of falling back to the internal Map
the class already maintains for exactly this kind of case.

Add a `require.cache` existence check alongside the existing
`isBuiltin` check in all three methods, so the fallback to the
internal Map also covers a missing `require.cache`, not just a
missing entry within it.

Note: when require.cache is unavailable, non-core modules are cached
in the internal Map instead, same as modules that are unexpectedly
missing from require.cache. This means the existing
delete-require.cache[...]-to-force-a-reload behavior (see
test/require-cache-inval.js) does not apply in that environment -
this is an inherent limitation of the environment, not a new gap
introduced by this fix.

Fixes nodejs#113
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.

ExportsCache.has: __require.cache[filename]; cannot read properties of undefined

1 participant