jdx/mise · error

an implied source entry key must not be empty

Error message

an implied source entry key must not be empty

What it means

If every component of the entry key is trivial (e.g. the key is `.`, `./`, or `~/` alone after expansion), the constructed relative source path is empty, which is not a valid file. `logical_source_path` rejects this rather than silently treating the dotfiles root as the source.

Solutions

  1. Replace the placeholder key with the actual relative source file path
  2. Add an explicit `source` field naming the file
  3. Remove the entry if it was accidental

Example fix

// before
"." = { variants = [ { target = "~/.zshrc" } ] }
// after
"~/.zshrc" = { source = "dotfiles/zshrc", variants = [ { target = "~/.zshrc" } ] }
Defensive patterns

Strategy: validation

Validate before calling

function keyNormalizesToEmpty(key) {
  const rel = key.replace(/^~\/?/, '').replace(/^[.\\/]+/, '');
  return rel.length === 0;
}

Type guard

const isNonEmptyRelativeKey = (key: string) => key.replace(/^[~.]\/?/, '').split(/[\\/]/).filter(c => c && c !== '.').length > 0;

Prevention

When it happens

Trigger: Entry key that normalizes to nothing, such as `"."` or `"~/"`, combined with `variants` and no explicit `source`.

Common situations: Copy-paste mistakes leaving a placeholder key like `"."`, or trimming a key down while debugging and leaving it empty of real components.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/system/files.rs:265

        bail!(
            "destination variants require an explicit source unless the entry key is a relative source path"
        );
    }
    let mut relative = PathBuf::new();
    for component in path.components() {
        match component {
            std::path::Component::Normal(component) => relative.push(component),
            std::path::Component::CurDir => {}
            std::path::Component::ParentDir => {
                bail!("an implied source entry key must not contain '..'");
            }
            std::path::Component::RootDir | std::path::Component::Prefix(_) => {
                bail!("an implied source entry key must be relative");
            }
        }
    }
    if relative.as_os_str().is_empty() {
        bail!("an implied source entry key must not be empty");
    }
    Ok(relative)
}

/// Inactive variants can contain another platform's absolute path syntax.
/// The selected destination is still checked with native path rules before use.
fn variant_target_is_absolute(target: &str) -> bool {
    let bytes = target.as_bytes();
    resolve_target_arg(target).is_absolute()
        || target.starts_with('/')
        || target.starts_with("\\\\")
        || (bytes.len() >= 3
            && bytes[0].is_ascii_alphabetic()
            && bytes[1] == b':'
            && matches!(bytes[2], b'/' | b'\\'))
}

/// One `[dotfiles]` whole-file entry as written in mise.toml.

View on GitHub (pinned to 533346cc37)