vitest-dev/vitest · error · Error
Failed to import custom OpenTelemetry SDK script (${options.
Error message
Failed to import custom OpenTelemetry SDK script (${options.sdkPath}): ${cause.message} What it means
Vitest's Traces constructor (packages/vitest/src/utils/traces.ts:67-69) dynamically imports the module referenced by experimental.openTelemetry.sdkPath when tracing is enabled. The path is resolved relative to the project root and converted to a file:// URL in resolveConfig.ts:972-977; Vitest does NOT transform this file. If that dynamic import rejects (bad path, syntax error, missing dependency, untranspiled TypeScript), the rejection is caught and re-thrown as this wrapped Error with the underlying cause's message, aborting worker initialization.
Source
Thrown at packages/vitest/src/utils/traces.ts:68
#initRecorded = false
constructor(options: TracesOptions) {
if (options.enabled) {
const apiInit = import('@opentelemetry/api').then((api) => {
const otel = {
tracer: api.trace.getTracer(options.tracerName || 'vitest'),
context: api.context,
propagation: api.propagation,
trace: api.trace,
SpanKind: api.SpanKind,
SpanStatusCode: api.SpanStatusCode,
}
this.#otel = otel
}).catch(() => {
throw new Error(`"@opentelemetry/api" is not installed locally. Make sure you have setup OpenTelemetry instrumentation: https://vitest.dev/guide/open-telemetry`)
})
const sdkInit = (options.sdkPath ? import(/* @vite-ignore */ options.sdkPath!) : Promise.resolve()).catch((cause) => {
throw new Error(`Failed to import custom OpenTelemetry SDK script (${options.sdkPath}): ${cause.message}`)
})
this.#init = Promise.all([sdkInit, apiInit]).then(([sdk]) => {
if (sdk != null) {
if (sdk.default != null && typeof sdk.default === 'object' && typeof sdk.default.shutdown === 'function') {
this.#sdk = sdk.default
}
else if (options.watchMode !== true && process.env.VITEST_MODE !== 'watch') {
console.warn(`OpenTelemetry instrumentation module (${options.sdkPath}) does not have a default export with a "shutdown" method. Vitest won't be able to ensure that all traces are processed in time. Try running Vitest in watch mode instead.`)
}
}
}).finally(() => {
this.#initEndTime = performance.now()
this.#init = null
})
}
}
public isEnabled(): boolean {View on GitHub (pinned to d568f8ce37)
Solutions
- Verify the sdkPath file exists and resolves against the configured `root` (it is resolved with path.resolve(root, sdkPath) and turned into a file:// URL); fix the path or move the file.
- Use a .js (ESM) file for the SDK module, and confirm `node ./otel.js` imports it cleanly from the project root — any error there is the same error Vitest reports.
- Install the OpenTelemetry packages the SDK module imports (`npm i @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-otlp-prope`).
- If you must use TypeScript, enable Node's native type stripping (Node >= 22.6 with --experimental-strip-types) or precompile the SDK to .js.
- Read the `${cause.message}` portion of the error — it is the raw import failure (MODULE_NOT_FOUND, SyntaxError, etc.) and names the exact culprit.
Example fix
// before (vitest.config.ts)
export default defineConfig({
test: { experimental: { openTelemetry: { enabled: true, sdkPath: './otel.ts' } } },
})
// after — ship a plain ESM .js file Node can import as-is
export default defineConfig({
test: { experimental: { openTelemetry: { enabled: true, sdkPath: './otel.js' } } },
})
// otel.js
import { NodeSDK } from '@opentelemetry/sdk-node'
const sdk = new NodeSDK({ /* ... */ })
sdk.start()
export default sdk Defensive patterns
Strategy: validation
Validate before calling
// Run BEFORE launching vitest with tracing enabled — verifies the SDK
// module is importable from the resolved project root.
import { pathToFileURL } from 'node:url'
import { resolve } from 'node:path'
async function assertOtelSdkLoads(root, sdkPath) {
if (!sdkPath) return
const abs = resolve(root, sdkPath)
const url = pathToFileURL(abs).toString()
try {
await import(url) // mirrors traces.ts:67 dynamic import
} catch (cause) {
throw new Error(
`experimental.openTelemetry.sdkPath (${sdkPath}) would fail to import: ${cause.message}`,
)
}
}
// await assertOtelSdkLoads(process.cwd(), './otel.js') Prevention
- Pre-author the SDK as a plain .js ESM file; avoid relying on Vite to transform it (it won't — the file is imported by Node directly).
- Smoke-test the module standalone with `node ./path/to/otel.js` from project root before wiring it into vitest.config.
- Keep the sdkPath relative to the configured `root` and re-verify it after moving files or changing roots in a monorepo.
- Pin the OpenTelemetry packages in package.json so a missing/changed peer dependency cannot break the SDK import silently.
When it happens
Trigger: Setting `test.experimental.openTelemetry.enabled = true` together with a non-empty `experimental.openTelemetry.sdkPath` whose target cannot be imported by plain Node.js: a .ts file without Node's type-stripping (--experimental-strip-types), a path that does not exist relative to the resolved project root, a module that itself throws on load (e.g. missing '@opentelemetry/sdk-node' dependency), or a module using bare-import specifiers Node cannot resolve.
Common situations: Pointing sdkPath at a .ts instrumentation file while running on Node < 22.6 (no native type stripping); moving/renaming the otel.js file without updating the config; adding the SDK config before running `npm i @opentelemetry/sdk-node ...`; relative path that resolves against the wrong root (monorepo with multiple roots); ESM/CJS mismatch inside the SDK module; forgetting that the file is loaded as-is by Node, not processed by Vite.
Related errors
- "@opentelemetry/api" is not installed locally. Make sure you
- Runner must export a default function, but got ${typeof mod.
- invalid diff config file ${config.diff}. Must have a default
- invalid snapshot serializer file ${file}. Must export a defa
- The ${provider.name} provider does not support tracing.
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/eba25364fc4bd3d2.json.
Report an issue: GitHub.