denoland/deno · error
failed to locate output for HTML entry
Error message
failed to locate output for HTML entry '{}'; {js_entry_name} What it means
During `deno bundle` of an HTML entrypoint, Deno looks up the JavaScript output esbuild produced for the page's script entry by its internal entry name. If no output file matches, this error fires: the HTML pipeline needs that JS output to rewrite the `<script>` tag and hash-rename files, so it cannot proceed.
Solutions
- Make sure the HTML references at least one real, non-empty local script module
- Use only `--outdir` with HTML entrypoints (drop `--output`)
- Clear the outdir and re-run to rule out stale hashed outputs colliding with the lookup
- If it persists with a plain page, file a deno issue with the HTML and exact command — this is an internal invariant
Example fix
<!-- before: empty script module --> <script type="module" src="./empty.js"></script> <!-- after: script with actual local code --> <script type="module" src="./main.js"></script>
Defensive patterns
Strategy: validation
Validate before calling
// Before bundling, verify every script entry referenced by the HTML is a non-empty local file
const html = await Deno.readTextFile("index.html");
for (const m of html.matchAll(/<script[^>]+src="([^"]+)"/g)) {
const url = new URL(m[1], import.meta.resolve("./index.html"));
if (url.protocol !== "file:") throw new Error(`script ${m[1]} is not local`);
const stat = await Deno.stat(url);
if (stat.size === 0) throw new Error(`script ${m[1]} is empty`);
} Prevention
- Keep at least one non-empty local script per HTML entrypoint
- Bundle HTML with only --outdir, never --output
- Rebuild into a clean outdir to avoid stale hashed outputs
When it happens
Trigger: Bundling an HTML page where esbuild emitted no matching JS entry output — the referenced script module is empty or fully externalized, output naming was altered, or the response shape changed between esbuild versions.
Common situations: An HTML page whose script points at an empty module or one with no local code; stale hashed outputs in the outdir from a previous run; mixing `--output` with HTML entrypoints.
Related errors
- esbuild exited before the rebuild completed
- expected a metafile to be present
- --outdir is required when bundling HTML entrypoints
- --output is not supported with HTML entrypoints; use…
- Deno.bundle() is not available in compiled binaries (`deno…
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/4117db53ea0d026f.
Report an issue: GitHub.
Appendix: source
Thrown at cli/tools/bundle/html.rs:509
}
let entry_name = format!("{}{}", self.entry_name, VIRTUAL_ENTRY_SUFFIX);
let js_entry_name = format!("{}.js", entry_name);
let mut js_out_no_hash = None;
let js_out = html_output_files
.get_and_update_path(&js_entry_name, |p, f| {
let p = p.to_string_lossy();
js_out_no_hash = Some(
p.replace(entry_name.as_str(), &original_entry_name)
.replace(&format!("-{}", f.hash), "")
.into(),
);
p.replace(entry_name.as_str(), &original_entry_name).into()
})
.ok_or_else(|| {
anyhow::anyhow!(
"failed to locate output for HTML entry '{}'; {js_entry_name}",
self.entry_name
)
})?;
let html_out_path = js_out_no_hash
.unwrap_or_else(|| js_out.clone())
.with_extension("html");
// esbuild emits the external/linked sourcemap (`*.js.map`) for the entry
// under the internal virtual-entry name. Rename it to match the renamed JS
// bundle (e.g. `index-HASH.js.map`) and fix the JS `sourceMappingURL`
// reference so the emitted output doesn't leak the `deno-bundle-html.entry`
// implementation detail. See denoland/deno#30750.
let map_entry_name = format!("{}.js.map", entry_name);
let mut old_map_name = None;
let new_map_out =
html_output_files.get_and_update_path(&map_entry_name, |p, _| {
old_map_name = pView on GitHub (pinned to 9ad36f7a2c)