{"record":{"id":"d75845866ef066e4","repo":"vitest-dev/vitest","slug":"vitest-expected-synchronous-evaluation-to-comple","errorCode":null,"errorMessage":"[vitest] Expected synchronous evaluation to complete for ${rootIdentifier}, but module status is \"${root.module.status}\". This is a bug in Vitest.","messagePattern":"\\[vitest\\] Expected synchronous evaluation to complete for (.+?), but module status is \"(.+?)\"\\. This is a bug in Vitest\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/runtime/vm/esm-executor.ts","lineNumber":302,"sourceCode":"          : `its dependency uses top-level await (${culprit})`,\n      )\n    }\n\n    for (const [identifier, entry] of scratch) {\n      if (entry.commit && !this.moduleCache.has(identifier)) {\n        this.moduleCache.set(identifier, entry.module)\n      }\n    }\n\n    // with no top-level await in the graph, evaluate() fulfills synchronously\n    // and an evaluation error lands on `status`/`error`, not on the promise\n    root.module.evaluate().catch(() => {})\n\n    if (root.module.status === 'errored') {\n      throw root.module.error\n    }\n    if (root.module.status !== 'evaluated') {\n      throw new Error(\n        `[vitest] Expected synchronous evaluation to complete for ${rootIdentifier}, but module status is \"${root.module.status}\". This is a bug in Vitest.`,\n      )\n    }\n    return root.module\n  }\n\n  // A cached module is reusable by the sync walker only when it is settled:\n  // anything else (a pending Promise or a module in 'unlinked' → 'evaluating')\n  // is a concurrent import() mid-flight that a synchronous require() can\n  // neither await nor safely link against.\n  private reuseSyncModule(\n    identifier: string,\n    cached: VMModule | Promise<VMModule>,\n  ): VMModule {\n    if (cached instanceof Promise) {\n      throw createConcurrentRequireError(identifier)\n    }\n    if (cached.status === 'errored') {","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/runtime/vm/esm-executor.ts#L284-L320","documentation":"Vitest's vm ESM executor asserts that a module graph containing no top-level await evaluates synchronously. After calling root.module.evaluate() it checks status: 'errored' rethrows the error, 'evaluated' is success, and any other status (e.g. 'evaluating', 'unlinked') trips this assertion. The message explicitly states it is a bug in Vitest, because with no async in the graph Node's vm SourceTextModule.evaluate() is contractually synchronous.","triggerScenarios":"A require(esm) import resolves a module whose hasAsyncGraph() reported false, yet root.module.evaluate() leaves status as anything other than 'errored' or 'evaluated'. Concretely this fires inside EsmExecutor when the sync module walker commits a graph it believed to be synchronous but Node disagrees, or when the module transitions states mid-evaluation due to re-entrant imports.","commonSituations":"Hitting an internal Vitest regression after upgrading Node.js (vm.SourceTextModule behavior changed), mixing require(esm) with modules that have hidden async (a dependency added top-level await), or a re-entrant dynamic import() racing the sync evaluation. Rare in stable releases; usually surfaces on nightly/edge Vitest or Node versions.","solutions":["Report it as a Vitest bug with the full module graph and the module that triggered the require(esm); include Vitest, Node, and OS versions.","Check whether any dependency in the import graph newly introduced top-level await (e.g. after an npm update) and refactor or mock it.","Try a different pool (threads/forks instead of vm) to confirm it is vm-executor specific: test.pool='threads'.","Downgrade Node.js to a known-good LTS to rule out a vm.SourceTextModule regression, or downgrade Vitest to the last working version."],"exampleFix":"// before: test file imports a dep that gained top-level await\nimport 'some-dep' // some-dep now has `await` at top level\n\n// after: avoid the sync require path by using dynamic import, or pin the dep\nimport('some-dep')","handlingStrategy":"try-catch","validationCode":"// Cannot be validated by callers reliably; it is an internal assertion.\n// Best pre-check: confirm the graph is truly synchronous before require(esm).\nconst hasAsync = (m) => m instanceof SourceTextModule && m.hasAsyncGraph()\nif (!hasAsync(root)) { /* safe to require */ }","typeGuard":"function isEvaluated(m) {\n  return m.status === 'evaluated' || m.status === 'errored'\n}","tryCatchPattern":"try {\n  executor.requireSync(identifier)\n} catch (e) {\n  if (String(e.message).includes('This is a bug in Vitest')) {\n    // file an issue; fall back to dynamic import\n    await import(identifier)\n  } else throw e\n}","preventionTips":["Keep imported graphs free of top-level await when using require(esm) in the vm pool.","Pin Node.js to an LTS version known to work with your Vitest version.","Reproduce on threads/forks pool to rule out vm-executor-specific regressions before reporting."],"tags":["vm","esm","internal-bug","synchronous-eval","top-level-await"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}