denoland/deno · error
module not found {}
Error message
module not found {} What it means
While converting a deno_graph ModuleGraph into an eszip v2 archive, every queued specifier is looked up with graph.try_get. Ok(None) means the specifier was scheduled for visiting but no module for it exists in the graph — graph and visit set disagree — and eszip creation aborts.
Source
Thrown at libs/eszip/v2.rs:1367
fn visit_module<'a>(
graph: &'a ModuleGraph,
module_kind_provider: &dyn ModuleKindResolver,
parser: CapturingEsParser,
transpile_options: &TranspileOptions,
emit_options: &EmitOptions,
modules: &mut LinkedHashMap<String, EszipV2Module>,
visited: ToVisit,
relative_file_base: Option<EszipRelativeFileBaseUrl>,
npm_packages: Option<&mut FromGraphNpmPackages>,
npm_snapshot: &ValidSerializedNpmResolutionSnapshot,
) -> Result<
Option<Box<dyn DoubleEndedIterator<Item = ToVisit<'a>> + 'a>>,
anyhow::Error,
> {
let module = match graph.try_get(visited.specifier()) {
Ok(Some(module)) => module,
Ok(None) => {
return Err(anyhow::anyhow!(
"module not found {}",
visited.specifier()
));
}
Err(err) => {
if visited.is_dynamic() {
// dynamic imports are allowed to fail
return Ok(None);
}
return Err(anyhow::anyhow!(
"failed to load '{}': {}",
visited.specifier(),
err
));
}
};
let specifier_key =View on GitHub (pinned to 89f33cbef2)
Solutions
- Rebuild the ModuleGraph from the same entrypoints immediately before creating the eszip, with full resolution and no skip/resolver overrides
- Ensure every dependency reachable from the entrypoints resolves during graph creation (run `deno cache` to surface errors first)
- If it persists, check for a version mismatch between deno_graph and eszip and align them
Example fix
// before — graph reused from an earlier build; visit set out of sync let eszip = eszip_from_graph(stale_graph, npm_packages, snapshot)?; // after — build the graph fresh from the same entrypoints, then convert let graph = deno_graph::create_graph(entrypoints.clone(), /* full options */).await; let eszip = eszip_from_graph(graph, npm_packages, snapshot)?;
Defensive patterns
Strategy: validation
Validate before calling
// before eszip::from_graph: every reachable dep must exist in the graph
let mut missing = Vec::new();
for module in graph.modules() {
for dep in module.dependencies() {
if let Some(spec) = dep.maybe_code.or(dep.maybe_type) {
if graph.try_get(spec).ok().flatten().is_none() {
missing.push(spec.clone());
}
}
}
}
assert!(missing.is_empty(), "modules missing from graph: {missing:?}"); Prevention
- Build the ModuleGraph and the eszip from the same entrypoints in the same run
- Do not reuse cached or partial graphs across deno_graph upgrades
- Run a full `deno cache` before compile-style pipelines to surface resolution gaps
When it happens
Trigger: Calling eszip's from_graph with a graph built with different options, different entrypoints, or skipped resolution than the visit list implies (cached/partial graphs, custom resolvers dropping modules, npm resolution skipped).
Common situations: Tooling that reuses a previously built ModuleGraph; `deno compile`-style pipelines after version upgrades where deno_graph and eszip disagree; graphs created with skip flags or stub resolvers.
Related errors
- failed to load '{}': {}
- unsupported media type {} for {}
- Could not resolve package req '{}' from graph because it was
- ${prefix}Linter plugin must be an object
- Invalid response
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/78e6ebb4a929eb3d.
Report an issue: GitHub.