vitejs/vite · critical · Error
Module "${url}" was mistakenly invalidated during fetch phas
Error message
Module "${url}" was mistakenly invalidated during fetch phase. What it means
Thrown in getModuleInformation when the server's fetchModule response includes a cache: true flag (indicating the module hasn't changed since last fetch) but the runner has no cached module for this URL (cachedModule is null or has no meta). This is a state inconsistency: the server assumes the client has the module cached, but the client's cache was cleared or never populated. It typically indicates a race condition between invalidation and fetching.
Source
Thrown at packages/vite/src/module-runner/runner.ts:298
const isCached = !!(typeof cachedModule === 'object' && cachedModule.meta)
const fetchedModule = // fast return for established externalized pattern
(
url.startsWith('data:') || this.isBuiltin?.(url)
? { externalize: url, type: 'builtin' }
: await this.transport.invoke('fetchModule', [
url,
importer,
{
cached: isCached,
startOffset: this.evaluator.startOffset,
},
])
) as ResolvedResult
if ('cache' in fetchedModule) {
if (!cachedModule || !cachedModule.meta) {
throw new Error(
`Module "${url}" was mistakenly invalidated during fetch phase.`,
)
}
return cachedModule
}
const moduleId =
'externalize' in fetchedModule
? fetchedModule.externalize
: fetchedModule.id
const moduleUrl = 'url' in fetchedModule ? fetchedModule.url : url
const module = this.evaluatedModules.ensureModule(moduleId, moduleUrl)
if ('invalidate' in fetchedModule && fetchedModule.invalidate) {
this.evaluatedModules.invalidateModule(module)
}
fetchedModule.url = moduleUrlView on GitHub (pinned to 89620f09af)
Solutions
- Avoid calling clearCache() while imports are in-flight; wait for all pending import() promises to settle first.
- If using HMR, let the HMR handler manage cache invalidation rather than calling clearCache() manually.
- Ensure your transport implementation correctly forwards the cache flag and doesn't falsely set it.
- In test environments, fully tear down the runner (await close()) before creating a new one rather than clearing mid-operation.
Example fix
// before — clearing cache during in-flight imports
runner.import('/src/a.ts') // in-flight
runner.clearCache() // wipes cache
// the server may now respond with { cache: true } for a module
// the runner no longer has -> throws
// after — await pending imports before clearing
await pendingImportPromise
runner.clearCache() Defensive patterns
Strategy: validation
Validate before calling
// Prevent concurrent clearCache + import races
let importCount = 0
let clearPending = false
async function guardedImport(runner, url) {
if (clearPending) throw new Error('Cache clear in progress')
importCount++
try {
return await runner.import(url)
} finally {
importCount--
}
}
async function guardedClearCache(runner) {
if (importCount > 0) {
console.warn('Waiting for in-flight imports before clearing cache')
// use a promise that resolves when importCount reaches 0
}
clearPending = true
runner.clearCache()
clearPending = false
} Try / catch
try {
await runner.import(url)
} catch (e) {
if (e.message.includes('mistakenly invalidated during fetch phase')) {
console.error('Cache race detected. Avoid calling clearCache() during imports.')
// may need to recreate the runner
}
throw e
} Prevention
- Never call clearCache() while import() promises are unresolved.
- Implement a mutex or counter to serialize cache clears with imports.
- Let the HMR handler manage invalidation rather than manual clearCache().
- In tests, fully close() and recreate the runner between test suites.
When it happens
Trigger: The runner's evaluatedModules cache is cleared (via clearCache()) while a concurrent fetch is in-flight. The server then responds with cache: true for a module the runner no longer has. Can also occur with custom transport implementations that incorrectly cache or replay fetch responses, or when multiple runner instances share a server that assumes state continuity.
Common situations: Calling clearCache() during HMR or SSR while async imports are pending. Race conditions in test environments where the runner is reset between tests but async operations from the previous test are still running. Custom transport middleware that incorrectly marks responses as cacheable.
Related errors
- [module runner] Dynamic access of "import.meta.env" is not s
- [module runner] "import.meta.resolve" is not supported.
- [module runner] "import.meta.glob" is statically replaced du
- HMR is not supported by this runner transport, but `hmr` opt
- Vite module runner has been closed.
AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03).
Data as JSON: /data/errors/a0a79e60c806d938.json.
Report an issue: GitHub.