jdx/mise · error

[bootstrap].config_roots did not match any config roots

Error message

[bootstrap].config_roots did not match any config roots

What it means

A [bootstrap] config declared config_roots patterns, but expanding them relative to the declaring config's directory yielded no existing directories. The bootstrap layer cannot resolve any config roots to merge.

Solutions

  1. Fix the patterns in [bootstrap].config_roots so they match existing directories under the declaring config's directory
  2. Check that the bootstrap config lives where its relative paths expect (patterns resolve against the declaring config's root)
  3. Create the referenced directories or remove stale entries
  4. Run with MISE_DEBUG=1 to inspect root expansion

Example fix

// before
[bootstrap]
config_roots = ["services/*"]
// after
[bootstrap]
config_roots = ["apps/*", "packages/*"]
Defensive patterns

Strategy: validation

Validate before calling

# check bootstrap patterns resolve to existing dirs relative to the declaring config
root=$(dirname "$(find . -name 'mise.toml' -path '*bootstrap*')")
for pat in $(yq '.bootstrap.config_roots[]' bootstrap-mise.toml); do
  ls -d "$root"/$pat >/dev/null 2>&1 || echo "$pat matches nothing under $root"
done

Type guard

// Rust
fn bootstrap_roots_exist(declaring_root: &Path, patterns: &[String]) -> bool {
    expand_bootstrap_config_roots(declaring_root, patterns)
        .map(|r| !r.is_empty())
        .unwrap_or(false)
}

Try / catch

// Rust
// bootstrap loading is internal; guard by pre-validating patterns:
if expand_bootstrap_config_roots(&root, &patterns)?.is_empty() {
    eprintln!("[bootstrap].config_roots match no directories under {root:?}");
}

Prevention

When it happens

Trigger: Loading a bootstrap config where expand_bootstrap_config_roots(declaring_root, patterns) returns an empty list (after sort/dedup) — patterns match no directories under the declaring config's root.

Common situations: [bootstrap].config_roots contains typos, points at directories that don't exist, or paths relative to the wrong declaring config location; often after repo restructuring or when the bootstrap config was copied from another project.

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/1e61b96ce44f30fe. Report an issue: GitHub.

Appendix: source

Thrown at src/config/mod.rs:1835

        BOOTSTRAP_CONFIG_ROOTS_REMOVE_AT,
        "bootstrap.config_roots",
        "`[bootstrap].config_roots` in {} is deprecated. Composing bootstrap configuration across independent roots needs more design; move bootstrap declarations into global or system configuration.",
        display_path(declaring_config)
    );
    if patterns.is_empty() {
        return Ok(vec![]);
    }

    let declaring_root = config
        .config_files
        .get(declaring_config)
        .expect("declaring bootstrap config is loaded")
        .config_root();
    let mut roots = expand_bootstrap_config_roots(&declaring_root, &patterns)?;
    roots.sort();
    roots.dedup();
    if roots.is_empty() {
        bail!("[bootstrap].config_roots did not match any config roots");
    }

    let mut base = config.config_files.clone();
    base.retain(|path, _| {
        is_global_config(path)
            || !path
                .canonicalize()
                .is_ok_and(|path| roots.iter().any(|root| path.starts_with(root)))
    });
    let mut maps = vec![BootstrapConfigMap {
        config_files: base,
        tera_ctx: config.tera_ctx.clone(),
        config_root: None,
        vars_results: config.vars_results_cached().cloned().unwrap_or_default(),
    }];
    let idiomatic_filenames = BTreeMap::new();
    for root in roots {
        let paths = config_paths_in_dir_with_filenames(&root, &DEFAULT_CONFIG_FILENAMES);

View on GitHub (pinned to 533346cc37)