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
- Add an explicit `source` to the entry so the key-based variants have a well-defined source.
- Or give every variant an explicit `target` so the key is not used as a target.
- 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
- Always set an explicit `source` when using destination variants.
- Or override `target` on every variant consistently.
- Lint configs so key-only entries never gain partial variants.
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
- destination variants with inline content are not supported
- [dotfiles]." / ": block content may not contain its own…
- [dotfiles]." ": mode symlink-each requires a directory…
- files
- " ". : block and source are mutually exclusive, ignoring…
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)