vitest-dev/vitest · error · Error
"@opentelemetry/api" is not installed locally. Make sure…
Error message
"@opentelemetry/api" is not installed locally. Make sure you have setup OpenTelemetry instrumentation: https://vitest.dev/guide/open-telemetry
What it means
When tracing is enabled, the Traces constructor dynamically imports @opentelemetry/api. Vitest does not bundle OpenTelemetry; it expects the package to be resolvable from the user's project. If the import rejects (module not found), the .catch at traces.ts:64-66 rethrows this error with a link to the setup guide. The rejection is deferred because it lives in a promise chain, so it surfaces when waitInit() is awaited or the init promise settles.
Solutions
- Install the package: npm i @opentelemetry/api (or the equivalent pnpm/yarn command).
- Verify resolution from the same CWD Vitest runs in: node -e "require.resolve('@opentelemetry/api')".
- Disable tracing (remove --experimental-traces / set experimentalTraces.enabled to false) if you do not need it.
- In a monorepo, hoist the dependency or add it to the workspace where Vitest executes.
Example fix
# before vitest --experimental-traces # throws # after npm i @opentelemetry/api vitest --experimental-traces
Defensive patterns
Strategy: validation
Validate before calling
function canResolveOtelApi() {
try {
require.resolve('@opentelemetry/api')
return true
} catch {
return false
}
}
if (config.experimentalTraces?.enabled && !canResolveOtelApi()) {
console.warn('Tracing requested but @opentelemetry/api is missing; disabling.')
config.experimentalTraces.enabled = false
} Try / catch
try {
await traces.waitInit()
} catch (e) {
if (e instanceof Error && /not installed locally/.test(e.message)) {
console.warn('OpenTelemetry tracing unavailable:', e.message)
} else {
throw e
}
} Prevention
- Add a pre-flight dependency check in CI before running traced test suites.
- Gate the experimentalTraces option behind a canResolveOtelApi() check.
- Pin @opentelemetry/api in package.json so an install pruning does not silently drop it.
- In monorepos, confirm the package resolves from the exact workspace that runs Vitest.
When it happens
Trigger: Enabling tracing via the experimentalTraces option (or --experimental-traces CLI flag) while @opentelemetry/api is not resolvable from the Vitest process. The constructor only attempts the import when options.enabled is true.
Common situations: Forgot to run npm i @opentelemetry/api; CI install step pruned dev dependencies; pnpm hoisting or monorepo isolation hides the package from the Vitest CWD; upgrading Vitest to a version that introduced tracing without updating the project deps.
Related errors
- Failed to import custom OpenTelemetry SDK script
- Cannot use the `bench` test-context fixture within a…
- Failed to load benchmark provider from
- pretty-format: Unknown option
- provider is not supported
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/2981a1e4288fd27d.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/utils/traces.ts:65
#noopContext = createNoopContext()
#initStartTime = performance.now()
#initEndTime = 0
#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
})
}View on GitHub (pinned to 1fa9837ec2)