jdx/mise · error

[monorepo].config_roots did not match any config roots

Error message

[monorepo].config_roots did not match any config roots

What it means

Monorepo config resolution matched zero directories for the glob patterns in [monorepo].config_roots. The patterns exist and are non-empty, but nothing on disk matches them, so mise cannot enumerate per-project config roots and aborts the monorepo operation.

Solutions

  1. Verify the glob patterns in [monorepo].config_roots match directories that actually contain mise config files
  2. Run from the actual monorepo root (patterns are expanded relative to monorepo_config.root)
  3. Check for typos or renamed directories and update the patterns
  4. Run with MISE_DEBUG=1 to see which roots were scanned

Example fix

// before
[monorepo]
config_roots = ["packages/*"]
// after (repo restructured)
[monorepo]
config_roots = ["libs/*", "apps/*"]
Defensive patterns

Strategy: validation

Validate before calling

# verify each config_root pattern matches at least one dir with a mise config
for pat in $(yq '.monorepo.config_roots[]' mise.toml); do
  ls -d $pat >/dev/null 2>&1 || echo "pattern $pat matches nothing"
done

Type guard

// Rust
fn patterns_match_any(root: &Path, patterns: &[String]) -> bool {
    patterns.iter().any(|p| glob_dir(root, p).next().is_some())
}

Try / catch

// Rust
match config.monorepo_config_root_dirs() {
    Ok(roots) => use(roots),
    Err(e) if e.to_string().contains("did not match any config roots") => {
        eprintln!("fix [monorepo].config_roots globs — no matches under monorepo root");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling monorepo_config_root_dirs (or its callers: monorepo_lockfile_root, monorepo_config_root_dirs_for_lockfiles, monorepo_config_root_dirs_with_filenames) when expand_config_root_dirs / expand_config_roots_with_filenames returns an empty vec — patterns match no existing subdirectories with configs.

Common situations: Typo'd or stale glob patterns (e.g. "packages/*" after restructuring to "libs/*"), patterns relative to the wrong monorepo root, or subdirectories present but containing no mise.toml/.mise.toml config.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/0e924ee52fbc8ebb. Report an issue: GitHub.

Appendix: source

Thrown at src/config/mod.rs:888

    ) -> Result<Vec<PathBuf>> {
        let monorepo_config = find_monorepo_config(&self.config_files)
            .ok_or_else(|| eyre!("no config file in scope sets monorepo_root = true"))?;
        let monorepo_root = monorepo_config.root;
        let patterns = monorepo_config
            .monorepo
            .config_roots
            .ok_or_else(|| eyre!("[monorepo].config_roots is required for monorepo operations"))?;
        if patterns.is_empty() {
            bail!("[monorepo].config_roots is required for monorepo operations");
        }
        let roots = match filenames {
            Some(filenames) => {
                expand_config_roots_with_filenames(&monorepo_root, &patterns, None, filenames)?
            }
            None => expand_config_root_dirs(&monorepo_root, &patterns, None)?,
        };
        if roots.is_empty() {
            bail!("[monorepo].config_roots did not match any config roots");
        }
        Ok(roots)
    }

    pub(crate) async fn monorepo_union_tool_request_set(
        self: &Arc<Self>,
    ) -> Result<ToolRequestSet> {
        Ok(self.monorepo_union().await?.tool_request_set)
    }

    /// Loads the union plus the monorepo root directory's own effective
    /// requests, for lockfile maintenance of the shared root lockfile.
    ///
    /// `monorepo_union` merges the root's configs underneath each declared
    /// config root, so a sibling's request for a short shadows the monorepo
    /// root's own request for it. Treating the union as the set of live
    /// requests for the root lockfile would then drop the root's request:
    /// `mise lock --upgrade` migrated a v0 monorepo lockfile without binding

View on GitHub (pinned to 533346cc37)