Summary
lru-cache@11.3.0 (PR #395) introduced a top-level await in the ESM build via src/diagnostics-channel-esm.mts:
export const [metrics, tracing] = await import('node:diagnostics_channel').then(...).catch(...)
This breaks any CJS module that transitively loads the ESM build of lru-cache, most notably jsdom via @asamuzakjp/css-color (which is pure ESM with no CJS entrypoint).
Dependency chain
jsdom (CJS)
→ @asamuzakjp/css-color (pure ESM, "type": "module")
→ lru-cache@11.3.0 (ESM build now has TLA)
→ ERR_REQUIRE_ASYNC_MODULE
Error
Error: require() cannot be used on an ESM graph with top-level await.
Use import() instead. To see where the top-level await comes from,
use --experimental-print-required-tla.
From jsdom/lib/jsdom/living/css/helpers/css-values.js
Requiring @asamuzakjp/css-color/dist/esm/index.js
This causes every Vitest test using jsdom to fail — no tests run at all.
Impact
This is affecting projects using Vitest + jsdom on Node 22+. The issue surfaced broadly today via Renovate/Dependabot lock file maintenance PRs that re-resolved lru-cache@^11.x to 11.3.0.
Related jsdom issues filed today:
Also related: #396 (Angular test runner memory leak from the same diagnostics-channel feature).
Why this happens
The exports map correctly routes require → CJS and import → ESM. However, when a CJS package (jsdom) requires a pure-ESM package (@asamuzakjp/css-color), Node resolves the ESM graph. Within that ESM graph, lru-cache's ESM entrypoint is loaded — which now contains TLA, making the entire graph impossible to require() synchronously.
Suggested fix
The comment in the source notes: "the first tick of metrics will be missed but that probably doesn't matter much." This suggests a non-blocking approach would be acceptable:
// Instead of TLA:
// export const [metrics, tracing] = await import('node:diagnostics_channel')...
// Use non-blocking init:
let metrics = dummyMetrics, tracing = dummyTracing;
import('node:diagnostics_channel').then(dc => {
metrics = dc.channel('lru-cache:metrics');
tracing = dc.tracingChannel('lru-cache:tracing');
}).catch(() => {});
export { metrics, tracing };
This preserves the non-Node fallback behavior without introducing TLA.
Workaround
Pin lru-cache to 11.2.7:
"pnpm": {
"overrides": {
"lru-cache": "11.2.7"
}
}
Versions
lru-cache: 11.3.0
jsdom: 29.0.1
@asamuzakjp/css-color: 5.0.1–5.1.5 (all affected)
- Node: 22+
- Vitest: 4.1.2
Summary
lru-cache@11.3.0(PR #395) introduced a top-levelawaitin the ESM build viasrc/diagnostics-channel-esm.mts:This breaks any CJS module that transitively loads the ESM build of
lru-cache, most notably jsdom via@asamuzakjp/css-color(which is pure ESM with no CJS entrypoint).Dependency chain
Error
This causes every Vitest test using jsdom to fail — no tests run at all.
Impact
This is affecting projects using Vitest + jsdom on Node 22+. The issue surfaced broadly today via Renovate/Dependabot lock file maintenance PRs that re-resolved
lru-cache@^11.xto 11.3.0.Related jsdom issues filed today:
Also related: #396 (Angular test runner memory leak from the same diagnostics-channel feature).
Why this happens
The
exportsmap correctly routesrequire→ CJS andimport→ ESM. However, when a CJS package (jsdom) requires a pure-ESM package (@asamuzakjp/css-color), Node resolves the ESM graph. Within that ESM graph,lru-cache's ESM entrypoint is loaded — which now contains TLA, making the entire graph impossible torequire()synchronously.Suggested fix
The comment in the source notes: "the first tick of metrics will be missed but that probably doesn't matter much." This suggests a non-blocking approach would be acceptable:
This preserves the non-Node fallback behavior without introducing TLA.
Workaround
Pin
lru-cacheto11.2.7:Versions
lru-cache: 11.3.0jsdom: 29.0.1@asamuzakjp/css-color: 5.0.1–5.1.5 (all affected)