denoland/deno · error

No matching module graph roots found.

Error message

No matching module graph roots found.

What it means

`deno sync-types` (also invoked internally by `deno check`/setup for stock tsc) builds a module graph over explicit root patterns you passed to discover external specifiers. Roots that live under the DENO_DIR cache, or under node_modules/.deno relative to the project root, are filtered out to avoid graphing tens of thousands of dependency files. If you passed explicit roots and every one of them was filtered away, it bails with this message.

Source

Thrown at cli/tools/installer/local.rs:325

    let roots: Vec<_> = roots
      .into_iter()
      .filter(|u| {
        let Ok(path) = u.to_file_path() else {
          return true;
        };
        if let Some(root) = &deno_dir_root
          && path.starts_with(root)
        {
          return false;
        }
        let rel = path.strip_prefix(&project_root).unwrap_or(&path);
        !rel.components().any(|c| {
          matches!(c.as_os_str().to_str(), Some("node_modules") | Some(".deno"))
        })
      })
      .collect();
    if has_explicit_roots && roots.is_empty() {
      bail!("No matching module graph roots found.");
    }

    // Build the graph error-tolerantly: `create_graph_with_options` populates
    // the graph and records unresolved modules as error entries without failing
    // the whole build (unlike `check_specifiers`, which validates and discards
    // everything on the first missing module). A real project always has some
    // broken file (dead example scripts, etc.); we want every specifier that
    // *did* resolve regardless.
    let graph_creator = factory.module_graph_creator().await?;
    // Silence warn-level diagnostics during this discovery build. It's an
    // internal step (not the user's `deno check`), and the graph the user
    // installed was already validated by `deno install` — re-emitting e.g.
    // "workspace member ... was not used" warnings here is just noise.
    let prev_log_level = log::max_level();
    log::set_max_level(log::LevelFilter::Error);
    let graph_result = graph_creator
      .create_graph_with_options(crate::graph_util::CreateGraphOptions {
        graph_kind: deno_graph::GraphKind::All,

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Point the roots at your own source files: `deno sync-types src/`
  2. If the project really lives under a directory named node_modules, move it or pass roots as file paths outside that tree
  3. Run `deno sync-types` with no roots to use '.' — the default project-wide discovery

Example fix

# before
deno sync-types node_modules/left-pad   # No matching module graph roots found.

# after
deno sync-types src/
Defensive patterns

Strategy: validation

Validate before calling

# pass roots that live in your own source tree:
deno sync-types src/
# sanity check before scripting:
ls src/*.ts >/dev/null || echo 'no project sources under src/'

Try / catch

Catch 'No matching module graph roots found'; retry `deno sync-types` with no root arguments (defaults to '.' over the project) — that path does not require the filter to keep anything.

Prevention

When it happens

Trigger: `deno sync-types <args>` where all matched files are inside node_modules/, a generated .deno/ dir, or DENO_DIR (e.g. `deno sync-types node_modules/...`, or a glob like `./vendor/**` that only matches filtered trees, or a project directory that itself sits under a path named node_modules).

Common situations: Pointing sync-types at installed dependencies instead of your own source; running from inside node_modules; overly broad globs whose only matches are generated/installed trees.

Related errors


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