jdx/mise · error

a provided source resolves to a path

Error message

a provided source resolves to a path

What it means

In `hosts_from_config`, a host's explicit `source` is resolved via `resolve_local_path(base, Some(source))?.expect("a provided source resolves to a path")`. The resolver returns an Option because a missing source can fall back to a default; but when the user provided one, None is treated as impossible. The panic fires when a provided source still resolves to None — e.g. the source is empty or resolves to nothing path-like.

Solutions

  1. Set a non-empty local filesystem path (absolute, or relative to the config base) in the host's `source` field
  2. Remove the `source` key entirely to inherit `default_source`
  3. Improve the code to return a real error naming the offending host/source instead of expect-ing

Example fix

// before
[remote.hosts.build]
source = ""
// after
[remote.hosts.build]
source = "~/project/build-host"
Defensive patterns

Strategy: validation

Validate before calling

if let Some(src) = &host.source {
    if src.trim().is_empty() {
        return Err(anyhow!("host '{name}' has an empty source"));
    }
}

Prevention

When it happens

Trigger: Configuring a remote host with a `source` value that `resolve_local_path` cannot turn into a path (empty string, or input the resolver filters out) at src/system/remote.rs:172.

Common situations: `source = ""` in a remote host config entry; templated source that expands to empty; copy-pasting a URL or ssh-style source where a local path is required.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/system/remote.rs:172

    let mut hosts = IndexMap::new();
    for cf in config.config_files.values() {
        let Some(bootstrap) = cf.bootstrap_config() else {
            continue;
        };
        let remote = bootstrap.remote;
        let base = cf.get_path().parent().unwrap_or_else(|| Path::new("."));
        let default_source = resolve_local_path(base, remote.source.as_deref())?;
        let default_mise_env = remote.mise_env;
        let default_install_mise = remote.install_mise.and_then(InstallMiseTomlConfig::path);
        let default_copy_links = remote.copy_links;
        let default_copy_link = remote.copy_link;
        for (name, host) in remote.hosts {
            if hosts.contains_key(&name) {
                continue;
            }
            let source = match host.source.as_deref() {
                Some(source) => resolve_local_path(base, Some(source))?
                    .expect("a provided source resolves to a path"),
                None => default_source.clone().unwrap_or(std::env::current_dir()?),
            };
            let identity_file = resolve_local_path(base, host.identity_file.as_deref())?;
            let mise_bin = resolve_local_path(base, host.mise_bin.as_deref())?;
            let mut exclude = default_excludes();
            exclude.extend_from_slice(layered_excludes);
            exclude.extend(host.exclude);
            let mut copy_link = default_copy_link.clone();
            copy_link.extend(host.copy_link);
            let host = RemoteHost {
                name: name.clone(),
                host: host.host,
                user: host.user,
                port: host.port,
                identity_file,
                source,
                mise_env: host
                    .mise_env

View on GitHub (pinned to 533346cc37)