nathan-watkins-unityai
03/16/2026, 7:57 PM@opentelemetry/instrumentation-net, @opentelemetry/instrumentation-express, @opentelemetry/instrumentation-ioredis spans in their traces after the v5 / ESM everywhere upgrade. We only seem to be getting @opentelemetry/instrumentation-pg post-upgrade. I'm always surprised otel-js and ESM is still [weird](https://github.com/open-telemetry/opentelemetry-js/issues/4933) in 2026.Ian Plunkett
03/24/2026, 6:25 PMnathan-watkins-unityai
03/24/2026, 6:30 PM--require while the [start](https://github.com/medplum/medplum/blob/main/packages/server/package.json#L25) command uses the --import flag. Do you all use the [--experimental-loader](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md#instrumentation-hook-required-for-esm) ?Ian Plunkett
03/24/2026, 6:35 PMnode --require ./packages/server/dist/otel/instrumentation.js packages/server/dist/index.jsnathan-watkins-unityai
04/23/2026, 2:55 PM--experimental-loader=@opentelemetry/instrumentation/hook.mjs to the startup command, per otel-js docs. I've confirmed it doesn't work for me without this. On Node 22, I was getting exit code 0 with the loader inlined in the startup command, so I think the loader was getting treated as the main module, so [if (import.meta.main)](https://github.com/medplum/medplum/blob/49a06ab18c252a1f93d049003f0e13da2f461c47/packages/server/src/index.ts#L58) wasn't truthy.
FWIW- Claude debugging was also locked in on a transitive dependency issue that existed in 5.0.15 but not in 5.1.8. Description below but I couldn't validate if that specifically was problematic. Hopfully one day soon OTel and ESM won't be a trainwreck.
@appsignal/opentelemetry-instrumentation-bullmq v0.7.3 depends on @opentelemetry/instrumentation ^0.52.1. Every other OTel package needs ^0.211.0+. Since pre-1.0 semver treats minor bumps as breaking, npm can't deduplicate -- it installs v0.52.1 at the root and nests v0.211+ under each package. Each nested copy brings its own import-in-the-middle, and each copy has an isolated hook registry. The ESM loader hook talks to one registry; the instrumentation hooks register in others. They never connect, so ESM imports of CJS packages like express and ioredis are never intercepted.
Upstream Medplum fixed this by updating to v0.8.0, which depends on ^0.213.0 -- compatible with everything else, so npm deduplicates to a single import-in-the-middle instance with one shared registry.