{"record":{"id":"430744304fd6b009","repo":"vitest-dev/vitest","slug":"cannot-import-mod-identifier-its-vm-context","errorCode":null,"errorMessage":"Cannot import \"${mod.identifier}\": its vm context was torn down.","messagePattern":"Cannot import \"(.+?)\": its vm context was torn down\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/runtime/vm/esm-executor.ts","lineNumber":67,"sourceCode":"    }\n    return { mime, code: Buffer.from(code, 'base64') }\n  }\n  if (!encoding || encoding === 'charset=utf-8') {\n    code = decodeURIComponent(code)\n  }\n  else if (encoding === 'base64') {\n    code = Buffer.from(code, 'base64').toString()\n  }\n  else {\n    throw new Error(`Invalid data URI encoding: ${encoding}`)\n  }\n  return { mime, code }\n}\n\nfunction getContextExecutor(mod: VMModule): ExternalModulesExecutor {\n  const vmContext = (mod.context as any)?.[VITEST_VM_CONTEXT_SYMBOL]\n  if (!vmContext) {\n    throw new Error(`Cannot import \"${mod.identifier}\": its vm context was torn down.`)\n  }\n  return vmContext.externalModulesExecutor\n}\n\nasync function staticImportModuleDynamically(specifier: string, referencer: VMModule): Promise<VMModule> {\n  return getContextExecutor(referencer).importModuleDynamically(specifier, referencer)\n}\n\nfunction staticInitializeImportMeta(meta: ImportMeta, mod: VMModule): void {\n  meta.url = mod.identifier\n  if (mod.identifier.startsWith('file:')) {\n    const filename = fileURLToPath(mod.identifier)\n    meta.filename = filename\n    meta.dirname = dirname(filename)\n  }\n  meta.resolve = (specifier: string, importer?: string | URL) => {\n    return getContextExecutor(mod).resolve(\n      specifier,","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/runtime/vm/esm-executor.ts#L49-L85","documentation":"Thrown by getContextExecutor when a module's vm context no longer carries the VITEST_VM_CONTEXT_SYMBOL property, meaning the context was disposed (torn down) while a dynamic import or import.meta.resolve is still being serviced against a module that lived in it. Vitest associates each test file's vm world with a context; once that file's run ends the context is torn down and any lingering reference fails fast.","triggerScenarios":"An asynchronous import() or `import.meta.resolve` triggered by a module in a finished test file resolves after the file's vm context has been disposed — e.g. a pending dynamic import or worker callback that fires during/after teardown. Reached via staticImportModuleDynamically and staticInitializeImportMeta's meta.resolve.","commonSituations":"Long-running async work (timers, workers, fetch) started in one test file that tries to dynamically import code after the file's run completed; sharing a module reference across files in a way that outlives its vm context; race conditions during fast bail/cancel where contexts are torn down while imports are mid-flight.","solutions":["Ensure async work that performs dynamic imports completes (or is cancelled) before the test file finishes — await it in the test or clean it up in afterAll.","Avoid caching modules or contexts across file boundaries; let each file's vm world be self-contained.","If using workers/subprocesses, terminate them in teardown so they cannot issue imports afterward.","Treat this as a symptom of a lifecycle leak: find what holds the module reference past teardown."],"exampleFix":"// before — dynamic import resolves after teardown\nlet mod\nbeforeAll(() => {\n  setTimeout(() => { mod = await import('./late') }, 10000)\n})\n\n// after — await inside the test lifecycle\nbeforeAll(async () => {\n  mod = await import('./late')\n})","handlingStrategy":"validation","validationCode":"// Ensure async work that imports modules completes before file teardown\nimport { beforeEach, afterEach } from 'vitest'\nlet pending: Promise<unknown> | null = null\nbeforeEach(() => { pending = null })\nafterEach(async () => { if (pending) await pending })\nfunction track(p: Promise<unknown>) { pending = p }","typeGuard":null,"tryCatchPattern":"try {\n  await import(/* @vite-ignore */ specifier)\n} catch (e) {\n  if (String(e?.message).includes('its vm context was torn down')) {\n    // the originating file's vm world is gone; abandon the import\n    return\n  }\n  throw e\n}","preventionTips":["Await all dynamic imports inside the test/beforeAll/afterAll that owns them.","Cancel timers, workers, and fetches in teardown so they cannot import later.","Do not share module references across files; keep each file's vm world self-contained.","Treat this error as a lifecycle-leak signal and fix the leak, not the symptom."],"tags":["vm","esm","lifecycle","async","imports"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}