jdx/mise · error

[monorepo].config_roots is required for monorepo operations

Error message

[monorepo].config_roots is required for monorepo operations

What it means

A monorepo operation (lockfile resolution or config-root discovery) ran but the monorepo config has no [monorepo].config_roots set, or it is set to an empty array. mise requires this key to know which subdirectories contain mise configs.

Solutions

  1. Add [monorepo] config_roots to the monorepo root mise.toml, e.g. config_roots = ["apps/*", "packages/*"]
  2. If templating produced an empty list, fix the template/condition so at least one pattern remains
  3. If you do not intend monorepo features, remove the [monorepo] table so normal config loading is used

Example fix

// before
[monorepo]
type = " Nx"
// after
[monorepo]
type = "nx"
config_roots = ["apps/*", "packages/*"]
Defensive patterns

Strategy: validation

Validate before calling

# shell pre-check before running mise monorepo commands
grep -q '^config_roots' mise.toml || echo "[monorepo].config_roots is missing"
# or in Rust, parse the config and check:
let patterns = cfg.monorepo.config_roots.as_ref();
let ok = matches!(patterns, Some(p) if !p.is_empty());

Type guard

// Rust
fn has_config_roots(cfg: &MonorepoConfig) -> bool {
    cfg.config_roots.as_ref().map_or(false, |p| !p.is_empty())
}

Try / catch

// Rust
match config.monorepo_config_root_dirs() {
    Ok(roots) => use(roots),
    Err(e) if e.to_string().contains("config_roots is required") => {
        bail!("add [monorepo].config_roots to the monorepo root mise.toml");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling monorepo_config_root_dirs (directly or via monorepo_lockfile_root, monorepo_config_root_dirs_for_lockfiles, monorepo_config_root_dirs_with_filenames) when monorepo.config.config_roots is None, or explicitly when it is an empty list.

Common situations: A monorepo root mise.toml declares [monorepo] metadata but omits config_roots; or config_roots was emptied by templating/environment so monorepo features (lockfiles, workspace tasks) cannot resolve.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at src/config/mod.rs:879

    /// Resolve `[monorepo].config_roots`.
    ///
    /// `None` matches any existing directory and is used for lockfile migration
    /// and routing. `Some(filenames)` requires a recognized config or idiomatic
    /// version file and is used for full monorepo union/task loading.
    pub(crate) fn monorepo_config_root_dirs(
        &self,
        filenames: Option<&[String]>,
    ) -> 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)
    }

View on GitHub (pinned to 533346cc37)