vitejs/vite · error · Error
Circular worker imports detected. Vite does not support it…
Error message
Circular worker imports detected. Vite does not support it. Import chain: ${newBundleChain.map((id) => prettifyUrl(id, config.root)).join(' -> ')} What it means
bundleWorkerEntry bundles a worker entry with rolldown, threading config.bundleChain to detect cycles. If the worker's import graph leads back to the same worker entry being bundled, Vite throws because recursively bundling a worker into itself is unsupported and would loop forever.
Solutions
- Read the printed import chain to find which worker is re-entered, then break that edge.
- Extract the shared code both workers use into a third non-worker module that neither worker entry re-imports.
- Avoid importing a worker file from another worker file; communicate via postMessage at runtime instead.
- Check barrel/index files for accidental re-exports of the worker entry.
Example fix
// before — workerA.ts imports workerB which imports workerA
// after — move shared logic to shared.ts imported by both
// workerA.ts: import { work } from './shared'
// workerB.ts: import { work } from './shared' Defensive patterns
Strategy: validation
Validate before calling
// Detect cycles among worker entries before bundling
function hasWorkerCycle(graph, start) {
const seen = new Set()
function visit(node, stack) {
if (stack.has(node)) return true
stack.add(node)
for (const next of graph[node] ?? []) if (visit(next, stack)) return true
stack.delete(node)
return seen.has(node) ? false : (seen.add(node), false)
}
return visit(start, new Set())
} Try / catch
try {
return await bundleWorkerEntry(config, id)
} catch (e) {
if (/Circular worker imports/.test(e.message)) {
logger.error(`Fix the cycle printed in the error before retrying.`)
}
throw e
} Prevention
- Keep worker entries isolated; share logic via non-worker modules.
- Run a dependency-graph check in CI for worker files.
- Avoid barrel files that re-export worker entries.
When it happens
Trigger: Worker A imports module M which imports Worker A again (or Worker A imports Worker B which imports Worker A). Each bundleWorkerEntry call pushes the input onto bundleChain; a repeat entry triggers the throw.
Common situations: Refactoring that made a worker re-import its own entry, circular deps between two worker files, or a barrel file that re-exports a worker entry that itself imports the barrel.
Related errors
- [vite]: Rolldown failed to resolve import
- Either "build.lib.entry" or the top-level "input" option is…
- Environment " " is not defined in the config.
- Failed to parse WASM file
- `input` cannot contain glob characters. They are reserved…
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/45f4e7e7d1a45f6e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/plugins/worker.ts:178
const workerOutputCaches = new WeakMap<ResolvedConfig, WorkerOutputCache>()
async function bundleWorkerEntry(
config: ResolvedConfig,
id: string,
): Promise<WorkerBundle> {
const input = cleanUrl(id)
const workerOutput = workerOutputCaches.get(config.mainConfig || config)!
workerOutput.removeBundleIfInvalidated(input)
const bundleInfo = workerOutput.getWorkerBundle(input)
if (bundleInfo) {
return bundleInfo
}
const newBundleChain = [...config.bundleChain, input]
if (config.bundleChain.includes(input)) {
throw new Error(
'Circular worker imports detected. Vite does not support it. ' +
`Import chain: ${newBundleChain.map((id) => prettifyUrl(id, config.root)).join(' -> ')}`,
)
}
// bundle the file as entry to support imports
const { rolldown } = await import('rolldown')
const { plugins, rolldownOptions, format } = config.worker
const workerConfig = await plugins(newBundleChain)
const workerEnvironment = new BuildEnvironment('client', workerConfig) // TODO: should this be 'worker'?
await workerEnvironment.init()
const chunkMetadataMap = new ChunkMetadataMap()
const workerBuildTarget = workerEnvironment.config.build.target
const bundle = await rolldown({
...rolldownOptions,
input,
plugins: workerEnvironment.plugins.map((p) =>View on GitHub (pinned to b4d66fee14)