denoland/deno · error
esbuild exited before the rebuild completed
Error message
esbuild exited before the rebuild completed
What it means
In watch mode, a rebuild sends a rebuild request to the persistent esbuild child process and then awaits its on_end event over a channel; recv() returning None means every sender was dropped - the esbuild process exited (crashed, was killed, binary vanished) before the rebuild finished (cli/tools/bundle/mod.rs:1176-1189).
Source
Thrown at cli/tools/bundle/mod.rs:1185
Ok(response)
}
async fn rebuild(&mut self) -> Result<BuildResponse, AnyError> {
match self.mode {
BundlingMode::OneShot => {
panic!("rebuild not supported for one-shot mode")
}
BundlingMode::Watch => {
log::trace!("sending rebuild request");
let _response = self
.client
.send_rebuild_request(0)
.await
.context("failed to send rebuild request to esbuild")?
.map_err(|e| message_to_error(&e, &self.cwd))?;
let response = self.on_end_rx.recv().await.ok_or_else(|| {
deno_core::anyhow::anyhow!(
"esbuild exited before the rebuild completed"
)
})?;
Ok(response.into())
}
}
}
async fn reload_specifiers(
&mut self,
changed_paths: &[PathBuf],
) -> Result<(), AnyError> {
self.reload_html_entrypoints(changed_paths)?;
self.plugin_handler.reload_specifiers(changed_paths).await?;
Ok(())
}
fn reload_html_entrypoints(View on GitHub (pinned to 89f33cbef2)
Solutions
- Restart the watch session (deno bundle --watch ...) - the child is respawned on startup
- Check for OOM kills: dmesg | grep -i oom or container memory limits; raise the limit or reduce --minify/workload
- Delete the cached esbuild binary directory under DENO_DIR so the next start re-downloads a clean copy
- If it recurs on current Deno with a reproducible trigger, report to denoland/deno with the esbuild version pin
Defensive patterns
Strategy: retry
Validate before calling
# Verify the cached esbuild binary is present and executable before long watch sessions
BIN_DIR=$(deno info 2>/dev/null | sed -n 's/.*DENO_DIR[^ ]* //p')
find "${DENO_DIR:-$HOME/.cache/deno}" -name esbuild -type f -executable -print 2>/dev/null || echo 'no cached esbuild binary - expect first-run download' Try / catch
# Supervised watch: restart the session when esbuild dies mid-rebuild until deno bundle --watch --outdir dist src/main.ts; do echo 'watch session died; restarting in 3s' >&2 if dmesg 2>/dev/null | grep -qi 'oom.*esbuild'; then echo 'OOM kill detected - raise memory limit' >&2; exit 1; fi sleep 3 done
Prevention
- Give CI containers enough memory for esbuild during watch/rebuild
- Exclude DENO_DIR from cleanup/antivirus scans during long sessions
- Prefer fresh watch sessions over multi-day ones; restart after upgrades
When it happens
Trigger: The esbuild child crashes mid-rebuild (native crash, OOM kill on constrained CI containers); the DENO_DIR-cached esbuild binary is deleted or corrupted while watching; system shutting down and the process group being torn down.
Common situations: Long watch sessions on memory-limited containers/CI where the kernel OOM-kills esbuild; antivirus/cleanup tools purging cache directories during the session; corrupted binary after a partial install (the atomic-rename logic guards this, but external deletion is still possible).
Related errors
- bundling failed
- could not get fetch esbuild binary; download it manually and
- failed to locate output for HTML entry '{}'; {js_entry_name}
- esbuild produced no JavaScript output
- The bench function must have a name
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/fba65545d4173b5b.
Report an issue: GitHub.