denoland/deno · error · anyhow::Error

module not found

Error message

module not found {}

What it means

When Deno serializes a module graph into an eszip archive (deno compile / deno bundle internals), every visited specifier must be found in the graph via graph.try_get(). Ok(None) means the specifier was queued for visiting but no module exists for it in the graph that was passed in — the graph and the visit queue disagree, so the build fails with 'module not found <specifier>'.

Solutions

  1. Re-run `deno cache <entry>` (or delete DENO_DIR and retry) so every specifier is freshly loaded before compiling
  2. Run `deno check <entry>` first — unresolved imports surface there with better diagnostics
  3. Ensure the graph passed to eszip was built from the same entry point and loader that produced the visit queue (don't mix graphs across runs)
  4. If a third-party dependency fails to resolve, pin a working version in the import map or package.json

Example fix

# before
deno compile src/mod.ts  # module not found https://example.com/lib.js

# after
deno cache src/mod.ts && deno compile src/mod.ts
Defensive patterns

Strategy: try-catch

Validate before calling

# Make every specifier resolvable BEFORE compiling
# (a successful cache guarantees graph.try_get() finds each module)
deno check --all src/mod.ts && deno cache src/mod.ts

Try / catch

// Tooling around `deno compile`
const p = new Deno.Command("deno", { args: ["compile", "-o", "app", "src/mod.ts"] });
const { success, stderr } = await p.output();
const err = new TextDecoder().decode(stderr);
if (!success && err.includes("module not found")) {
  const spec = err.match(/module not found (\S+)/)?.[1];
  // re-cache just that specifier: deno cache <spec>, then retry
}

Prevention

When it happens

Trigger: Building an eszip from a graph that was constructed with a different entry point or with errors skipped; a dependency edge (e.g. from a resolved import in a cached package.json or import map) pointing at a specifier never loaded into the graph; file deleted or remote module evicted from cache between graph construction and serialization.

Common situations: deno compile failing after a DENO_DIR cache purge or when --no-remote-style restrictions excluded a module; mismatched graphs after editing entry points while reusing a stale in-process graph; tooling built on the eszip crate passing a graph and visitor set built from separate runs.

Related errors


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

Appendix: 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 9ad36f7a2c)