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

  1. Rebuild the ModuleGraph from the same entrypoints immediately before creating the eszip, with full resolution and no skip/resolver overrides
  2. Ensure every dependency reachable from the entrypoints resolves during graph creation (run `deno cache` to surface errors first)
  3. 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

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


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/78e6ebb4a929eb3d. Report an issue: GitHub.