{"record":{"id":"eba25364fc4bd3d2","repo":"vitest-dev/vitest","slug":"failed-to-import-custom-opentelemetry-sdk-script","errorCode":null,"errorMessage":"Failed to import custom OpenTelemetry SDK script (${options.sdkPath}): ${cause.message}","messagePattern":"Failed to import custom OpenTelemetry SDK script \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/utils/traces.ts","lineNumber":68,"sourceCode":"  #initRecorded = false\n\n  constructor(options: TracesOptions) {\n    if (options.enabled) {\n      const apiInit = import('@opentelemetry/api').then((api) => {\n        const otel = {\n          tracer: api.trace.getTracer(options.tracerName || 'vitest'),\n          context: api.context,\n          propagation: api.propagation,\n          trace: api.trace,\n          SpanKind: api.SpanKind,\n          SpanStatusCode: api.SpanStatusCode,\n        }\n        this.#otel = otel\n      }).catch(() => {\n        throw new Error(`\"@opentelemetry/api\" is not installed locally. Make sure you have setup OpenTelemetry instrumentation: https://vitest.dev/guide/open-telemetry`)\n      })\n      const sdkInit = (options.sdkPath ? import(/* @vite-ignore */ options.sdkPath!) : Promise.resolve()).catch((cause) => {\n        throw new Error(`Failed to import custom OpenTelemetry SDK script (${options.sdkPath}): ${cause.message}`)\n      })\n      this.#init = Promise.all([sdkInit, apiInit]).then(([sdk]) => {\n        if (sdk != null) {\n          if (sdk.default != null && typeof sdk.default === 'object' && typeof sdk.default.shutdown === 'function') {\n            this.#sdk = sdk.default\n          }\n          else if (options.watchMode !== true && process.env.VITEST_MODE !== 'watch') {\n            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.`)\n          }\n        }\n      }).finally(() => {\n        this.#initEndTime = performance.now()\n        this.#init = null\n      })\n    }\n  }\n\n  public isEnabled(): boolean {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/utils/traces.ts#L50-L86","documentation":"When a custom sdkPath is supplied in tracing options, Vitest dynamically imports that module to obtain an OpenTelemetry SDK with a default export exposing a shutdown method. If that import fails for any reason, the .catch at traces.ts:67-69 rethrows an error that embeds the underlying cause's message so the failure is attributable.","triggerScenarios":"Setting experimentalTraces with an sdkPath that cannot be imported: the path does not resolve, the module throws during evaluation, it uses incompatible module syntax (CJS in an ESM dynamic-import context), or it references a missing dependency.","commonSituations":"Wrong relative path (not relative to project root); typo in the option; SDK file uses CommonJS only; SDK depends on a package not installed; path correct in dev but broken in CI due to a different CWD.","solutions":["Reproduce the import standalone to see the real cause: node --input-type=module -e \"import('<sdkPath>').then(console.log).catch(console.error)\".","Fix the syntax/runtime error reported in cause.message.","Use an absolute path or a path resolvable from the Vitest process root.","Drop sdkPath if you do not need a custom SDK; rely on the default OpenTelemetry setup."],"exampleFix":"// before\nexperimentalTraces: { enabled: true, sdkPath: './otel.ts' }  // wrong path\n\n// after\nexperimentalTraces: { enabled: true, sdkPath: './tracing/otel.ts' }","handlingStrategy":"try-catch","validationCode":"async function sdkModuleLoads(p) {\n  if (!p) return true\n  try {\n    const mod = await import(/* @vite-ignore */ p)\n    return mod && typeof mod.default?.shutdown === 'function'\n  } catch {\n    return false\n  }\n}\n// gate the option:\nif (config.experimentalTraces?.sdkPath && !(await sdkModuleLoads(config.experimentalTraces.sdkPath))) {\n  delete config.experimentalTraces.sdkPath\n}","typeGuard":"function isOtelSdk(mod: unknown): mod is { default: { shutdown: () => Promise<void>; forceFlush?: () => Promise<void> } } {\n  return !!mod && typeof mod === 'object'\n    && typeof (mod as any).default?.shutdown === 'function'\n}","tryCatchPattern":"try {\n  await traces.waitInit()\n} catch (e) {\n  if (e instanceof Error && /Failed to import custom OpenTelemetry SDK/.test(e.message)) {\n    console.warn('Custom OTel SDK not loaded; continuing without it:', e.message)\n  } else {\n    throw e\n  }\n}","preventionTips":["Resolve sdkPath to an absolute path before passing it to Vitest.","Keep the SDK module side-effect free and ESM-compatible so dynamic import cannot throw at load time.","Run a standalone import smoke test in CI for the configured sdkPath.","Log cause.message when surfacing the error; it usually names the real failure (missing file, missing dep, syntax)."],"tags":["opentelemetry","tracing","configuration","dynamic-import"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}