rolldown/rolldown · error
ModuleLoader: failed to send build errors - main thread…
Error message
ModuleLoader: failed to send build errors - main thread terminated while processing module errors
What it means
Like the external variant, a normal module task that fails sends `BuildErrors` to the loader main thread via a channel. The `expect` panics if the receiver is gone — the main thread terminated (panic, abort, cancellation) while the module task was still reporting its errors.
Solutions
- Find and fix the primary/first error in the logs — this panic is a secondary symptom
- Avoid cancelling the build mid-flight; let it emit its errors normally
- Report to rolldown if the main thread dies without emitting a primary error
Defensive patterns
Strategy: try-catch
Try / catch
try {
await rolldown(input);
} catch (e) {
// treat this as secondary; find the first real module error in stderr
console.error('primary error:', e);
} Prevention
- Resolve the first-reported module error; the channel panic follows it
- Let builds run to completion rather than cancelling on the first failure
- Keep transform/load hooks free of throws that can kill the main thread
When it happens
Trigger: Main module-loader loop drops `rx` before all module tasks finish — caused by a fatal error elsewhere in the build, a panic in the loader, or cancellation of the build future.
Common situations: Another module's hard failure shuts down the loader while siblings are still erroring; user-initiated cancellation; plugins panicking in the main thread.
Related errors
- ModuleLoader: failed to send external module build errors -…
- Module tasks did't complete as expected
- barrel module should exist
- Barrel module should exists in full build
- Barrel module should exists in partial build
AI-assisted analysis of rolldown/rolldown@91b44b9d7b (2026-09-07).
Data as JSON: /api/errors/6ea0465beaf1b454.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rolldown/src/module_loader/module_task.rs:87
module_idx: idx,
resolved_id,
owner,
is_user_defined_entry,
asserted_module_type: assert_module_type,
flat_options,
magic_string_tx,
}
}
#[tracing::instrument(name="NormalModuleTask::run", level = "trace", skip_all, fields(module_id = %self.resolved_id.id))]
pub async fn run(mut self) {
if let Err(errs) = self.run_inner().await {
self.ctx.plugin_driver.mark_context_load_modules_loaded(self.resolved_id.id.clone());
self
.ctx
.tx
.send(ModuleLoaderMsg::BuildErrors(errs.into_vec().into_boxed_slice()))
.expect("ModuleLoader: failed to send build errors - main thread terminated while processing module errors");
}
}
async fn run_inner(&mut self) -> BuildResult<()> {
let id = self.resolved_id.id.clone();
self.ctx.plugin_driver.set_module_info(
&id,
Arc::new(ModuleInfo {
code: None,
id: id.clone(),
is_entry: self.is_user_defined_entry,
importers: FxIndexSet::default(),
dynamic_importers: FxIndexSet::default(),
imported_ids: FxIndexSet::default(),
dynamically_imported_ids: FxIndexSet::default(),
exports: vec![],
input_format: ExportsKind::None,View on GitHub (pinned to 91b44b9d7b)