Skip to content

fix(instrumentation): lazily initialize require-in-the-middle for empty instrumentations#6590

Open
biw wants to merge 1 commit into
open-telemetry:mainfrom
biw:biw/lazy-ritm-init
Open

fix(instrumentation): lazily initialize require-in-the-middle for empty instrumentations#6590
biw wants to merge 1 commit into
open-telemetry:mainfrom
biw:biw/lazy-ritm-init

Conversation

@biw
Copy link
Copy Markdown

@biw biw commented Apr 14, 2026

Which problem is this PR solving?

InstrumentationBase currently creates RequireInTheMiddleSingleton eagerly during construction.

That means simply instantiating a Node instrumentation can install the global require-in-the-middle hook, even when that instrumentation does not declare any modules to patch in init().

This is a problem for bundled ESM applications, including Electron main-process apps, which use createRequire(import.meta.url) for native .node addons.

In this case, an instrumentation which only uses diagnostics_channel and does not need module patching can still cause require-in-the-middle to be installed. In bundled ESM environments, that unnecessary hook can lead to runtime failures when the app later uses createRequire(), for example ReferenceError: require is not defined.

This PR makes RequireInTheMiddleSingleton lazy. It is now only initialized when an instrumentation actually has module definitions to register.

That keeps module-patching instrumentations working as before, while avoiding an unnecessary global side effect for instrumentations that do not use require-in-the-middle.

Short description of the changes

  • Make RequireInTheMiddleSingleton lazy in InstrumentationBase
  • Skip require-in-the-middle initialization entirely when init() returns no module definitions
  • Add unit tests covering instrumentations with empty init() results

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Targeted tests run in experimental/packages/opentelemetry-instrumentation:

  • npx mocha -r ts-node/register test/node/InstrumentationBase.test.ts
  • npx mocha -r ts-node/register test/node/RequireInTheMiddleSingleton.test.ts

Added coverage verifies that RequireInTheMiddleSingleton.getInstance() is not called:

  • during construction of an instrumentation whose init() returns no module definitions
  • during enable() for that same kind of instrumentation

I also smoke-tested this change against a local Electron repro using Sentry + bundled ESM + createRequire(import.meta.url). With this patch applied, the repro no longer throws require is not defined, and the diagnostics-channel-based fetch instrumentation still remains enabled.

Checklist:

  • Followed the style guidelines of this project
  • Unit tests have been added
  • Documentation has been updated

@biw biw requested a review from a team as a code owner April 14, 2026 23:38
@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented Apr 14, 2026

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: biw / name: Ben Williams (531943b)

@timfish
Copy link
Copy Markdown
Contributor

timfish commented Apr 15, 2026

In bundled ESM environments, that unnecessary hook can lead to runtime failures when the app later uses createRequire(), for example ReferenceError: require is not defined

It's not clear why ESM, bundling and require-in-the-middle causes the above to occur. Do you have a reproduction to try?

It feels like this PR works around an issue rather than actually finding and fixing the root cause!

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.76%. Comparing base (8ee2a8b) to head (531943b).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6590   +/-   ##
=======================================
  Coverage   95.76%   95.76%           
=======================================
  Files         375      375           
  Lines       12739    12739           
  Branches     3013     3013           
=======================================
  Hits        12200    12200           
  Misses        539      539           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@timfish
Copy link
Copy Markdown
Contributor

timfish commented Apr 15, 2026

Ah, I see that essentially your PR here is a reproduction of the issue. I'll take a look!

@timfish
Copy link
Copy Markdown
Contributor

timfish commented Apr 15, 2026

@biw your example from the Electron PR referenced some really old dependencies. When I updated everything to below, it doesn't result in a runtime error.

  "dependencies": {
    "electron-squirrel-startup": "^1.0.1"
  },
  "devDependencies": {
    "@sentry/electron": "7.11.0",
    "@sentry/vue": "10.47.0",
    "@vitejs/plugin-vue": "^6.0.6",
    "electron": "^41.2.0",
    "electron-vite": "^5.0.0",
    "vite": "^8.0.8",
    "vue": "^3.5.32"
  }

If you can supply a failing reproduction of the issue I might be able to help further.

@biw
Copy link
Copy Markdown
Author

biw commented Apr 15, 2026

@biw your example from the Electron PR referenced some really old dependencies. When I updated everything to below, it doesn't result in a runtime error.

  "dependencies": {
    "electron-squirrel-startup": "^1.0.1"
  },
  "devDependencies": {
    "@sentry/electron": "7.11.0",
    "@sentry/vue": "10.47.0",
    "@vitejs/plugin-vue": "^6.0.6",
    "electron": "^41.2.0",
    "electron-vite": "^5.0.0",
    "vite": "^8.0.8",
    "vue": "^3.5.32"
  }

If you can supply a failing reproduction of the issue I might be able to help further.

Good catch, I copied those from another example in the sentry-electron, but I can recreate it not failing when upgrading the dependencies. I will work on a full example that does experience the issue. Thanks for your review and patience!

@pichlermarc
Copy link
Copy Markdown
Member

Hi @biw - were you able to repro this on more recent versions? 🙂

@timfish
Copy link
Copy Markdown
Contributor

timfish commented May 11, 2026

I would say this should be closed.

Rather than init require-in-the-middle lazily, there should be a way to create Node instrumentations that don't use require-in-the-middle and import-in-the-middle at all. ie. some higher level base instrumentation that doesn't expect module hooking. This would be useful for instrumentations that use TracingChannel!

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.

3 participants