jdx/mise · error

output pattern {output:?} matched no files

Error message

output pattern {output:?} matched no files

What it means

When resolving output roots with require_matches, each positive output glob pattern must match at least one existing file (or be a valid literal path). If a glob matches nothing, mise treats the cache config as invalid rather than silently caching an empty artifact.

Source

Thrown at src/task/task_cache.rs:1297

                for entry in glob_walk(&root.join(expanded), false)? {
                    let path = match entry {
                        Ok(entry) => entry.into_path(),
                        Err(err) => match symlink_walk_error_path(&err) {
                            Some(path) => path.to_path_buf(),
                            None => return Err(err.into()),
                        },
                    };
                    glob_matched = true;
                    let rel = path.strip_prefix(root)?.to_path_buf();
                    ensure_safe_relative(&rel)?;
                    let is_dir = fs::symlink_metadata(&path)?.is_dir();
                    if is_output(&matcher, &path, is_dir) {
                        resolved.insert(rel);
                    }
                }
            }
            if require_matches && !glob_matched {
                bail!("output pattern {output:?} matched no files");
            }
        } else {
            let rel = PathBuf::from(&output);
            let abs = root.join(&rel);
            let is_dir = fs::symlink_metadata(&abs)
                .map(|metadata| metadata.is_dir())
                .unwrap_or(false);
            if !is_output(&matcher, &abs, is_dir) {
                continue;
            }
            if require_matches && !abs.exists() && fs::symlink_metadata(&abs).is_err() {
                bail!("output {} does not exist", rel.display());
            }
            resolved.insert(rel);
        }
    }
    Ok(resolved.into_iter().collect())
}

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Fix the glob so it matches actual files produced by the task (verify with ls the matching files exist)
  2. Run the task's output-producing command before validation, or only validate after a build
  3. Remove outputs patterns for artifacts the task no longer produces
  4. Check for case sensitivity/platform path differences in the pattern

Example fix

# before
outputs = ["build/bin/app-linux"]
# after
outputs = ["build/bin/app"]  # matches the actually produced binary
Defensive patterns

Strategy: validation

Validate before calling

let matches: Vec<_> = glob(pattern)?
    .filter_map(Result::ok)
    .collect();
if matches.is_empty() {
    return Err(format!("output pattern {pattern:?} matches no files"));
}

Type guard

fn pattern_matches_files(pattern: &str) -> bool {
    glob::glob(pattern).map(|it| it.count() > 0).unwrap_or(false)
}

Prevention

When it happens

Trigger: An outputs pattern like "build/*.zip" is validated (validation path calls resolve_output_roots with require_matches = true) but no files on disk match — the glob is wrong, or the output-producing step hasn't run yet during validation.

Common situations: Typos in glob patterns or wrong directory names; declaring outputs for files only produced in CI but validating locally; outputs that depend on a build step never executed; case-sensitive filename mismatches on Linux.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/d1388d609bad6331. Report an issue: GitHub.