Skip to content

fix: do not mask runtime errors with require() fallback#200

Open
mahmoodhamdi wants to merge 3 commits intopinojs:mainfrom
mahmoodhamdi:fix/import-error-hidden-by-require-retry
Open

fix: do not mask runtime errors with require() fallback#200
mahmoodhamdi wants to merge 3 commits intopinojs:mainfrom
mahmoodhamdi:fix/import-error-hidden-by-require-retry

Conversation

@mahmoodhamdi
Copy link

Summary

  • Prevents runtime errors (ReferenceError, TypeError, SyntaxError, etc.) from being masked by the realRequire() fallback in the worker module loader
  • The pkg bundler fallback continues to work as before for plain Error instances

Context

Closes #156

When a worker module has a runtime error (e.g., ReferenceError from an undeclared variable), the error has code === undefined. This caused it to match the pkg bundler fallback condition, which then tried realRequire(). If that also failed (e.g., with ERR_REQUIRE_ESM), the original error was rethrown — but if realRequire() happened to succeed for a different reason, the runtime error was silently swallowed.

The fix checks error.constructor !== Error to distinguish runtime errors (which are subclasses like ReferenceError, TypeError) from plain Error instances thrown by the pkg bundler.

Test plan

  • All 51 existing + new tests pass (3 skipped for yarn)
  • New test verifies that a ReferenceError in a worker module is properly surfaced
  • Backwards compatible — pkg bundler errors (plain Error with code === undefined) still fall through to realRequire()

When realImport() fails with a runtime error (ReferenceError,
TypeError, etc.) from the loaded module, the error.code is
undefined. Previously this caused the code to fall through to the
realRequire() retry path, which masked the original error with
an unrelated ERR_REQUIRE_ESM or similar error.

Now runtime errors (where error.constructor !== Error) are rethrown
immediately, while plain Error instances from pkg bundling still
fall through to the require() fallback as before.

Closes pinojs#156
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

lib/worker.js Outdated
// These have no error code but indicate real bugs in the loaded module.
// Only fall back to require for plain Error instances from module loading.
// More info at: https://github.com/pinojs/thread-stream/issues/156
if (error.code === undefined && error.constructor !== Error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be a bit more tight and just check the actual error code being thrown when real require is triggered.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I'll update this to check the actual error code from realRequire instead. If realRequire fails with something other than MODULE_NOT_FOUND, it means the module was found but had a runtime error — so we should surface that.

Will push an update shortly.

Check the actual error code from realRequire to distinguish
module resolution errors (MODULE_NOT_FOUND) from runtime errors
in the loaded module (ReferenceError, TypeError, etc.).
Use instanceof checks for ReferenceError, TypeError, and RangeError
instead of checking requireError.code. This correctly handles the case
where require fails on ESM files (non-MODULE_NOT_FOUND errors that
are not runtime errors).
@mahmoodhamdi
Copy link
Author

Pushed another update — the previous approach (requireError.code !== "MODULE_NOT_FOUND") broke the "syntax error" test because .mjs files that fail to require throw a non-MODULE_NOT_FOUND error (ESM loading error), not a runtime error.

Now using instanceof checks for ReferenceError, TypeError, and RangeError to precisely identify runtime errors from the loaded module. This correctly handles:

  • ReferenceError in module (test/reference-error.js) → surfaced to user
  • SyntaxError in .mjs file (test/syntax-error.mjs) → original import error surfaced
  • Bundler/pkg loading failures → falls through to require successfully
  • MODULE_NOT_FOUND from require → original import error surfaced

All 51 tests pass (3 skipped for yarn).

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.

Import Errors Hidden by real-require Retry

2 participants