jdx/mise · error

destination variants require an explicit source when any…

Error message

destination variants require an explicit source when any variant uses the entry key as its target

What it means

Thrown by `validate_file_variants` when destination variants are used but some variants omit `target`, and the entry has no explicit `source`. In that case the entry key itself becomes the implied target for variants that lack an override, and the tool would have to derive the source from that key via logical_source_path; to keep behavior explicit, the tool requires an explicit `source` whenever any variant uses the entry key as its target.

Solutions

  1. Add an explicit `source` to the entry so the key-based variants have a well-defined source.
  2. Or give every variant an explicit `target` so the key is not used as a target.
  3. Or rename the entry key to the logical source path the tool would otherwise infer.

Example fix

// before
[[files]]
key = "zshrc"
[[files.variants]]
target = "~/.config/zsh/.zshrc"
[[files.variants]]  # no target: uses key
// after
[[files]]
key = "zshrc"
source = "zshrc"
[[files.variants]]
target = "~/.config/zsh/.zshrc"
[[files.variants]]
Defensive patterns

Strategy: validation

Validate before calling

let has_override = entry.variants.iter().any(|v| v.target.is_some());
let all_overridden = entry.variants.iter().all(|v| v.target.is_some());
if has_override && entry.source.is_none() && !all_overridden {
    bail!("entry {} needs explicit source when some variants use the key as target", entry.key);
}

Type guard

fn needs_explicit_source(entry: &FileEntry) -> bool {
    let any = entry.variants.iter().any(|v| v.target.is_some());
    let all = entry.variants.iter().all(|v| v.target.is_some());
    any && !all && entry.source.is_none()
}

Prevention

When it happens

Trigger: Config with `has_target_override == true`, `source == None`, and at least one variant without `target` (so it falls back to the entry key as destination) — `!variants.iter().all(|v| v.target.is_some())` inside the implied-source branch.

Common situations: Adding one platform-specific variant with an override to a key-based entry that previously had no source and no variants; assuming all variants inherit the key path while partially specifying targets; refactoring entries and dropping the source field.

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

Appendix: source

Thrown at src/system/files.rs:224

fn validate_file_variants(
    target: &str,
    source: Option<&str>,
    content: Option<&str>,
    mode: Option<&str>,
    variants: &[FileVariant],
) -> Result<Option<PathBuf>> {
    let selectors: Vec<_> = variants.iter().map(|v| v.selector.clone()).collect();
    crate::system::history::select::validate(&selectors)?;
    let has_target_override = variants.iter().any(|v| v.target.is_some());
    if has_target_override && mode == Some("track") {
        bail!("target overrides are not supported with mode = \"track\"");
    }
    if has_target_override && content.is_some() {
        bail!("destination variants with inline content are not supported");
    }
    let implied_source = if has_target_override && source.is_none() {
        if !variants.iter().all(|v| v.target.is_some()) {
            bail!(
                "destination variants require an explicit source when any variant uses the entry key as its target"
            );
        }
        Some(logical_source_path(target)?)
    } else {
        None
    };
    if variants.is_empty() && resolve_target_arg(target).is_relative() {
        bail!("target must be absolute or start with ~/");
    }
    for variant in variants {
        let destination = variant.target.as_deref().unwrap_or(target);
        if !variant_target_is_absolute(destination) {
            bail!("variant target must be absolute or start with ~/");
        }
    }
    Ok(implied_source)
}

View on GitHub (pinned to 533346cc37)