{"record":{"id":"ffad923fcb37e692","repo":"jdx/mise","slug":"target-must-be-absolute-or-start-with","errorCode":null,"errorMessage":"target must be absolute or start with ~/","messagePattern":"target must be absolute or start with ~/","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/files.rs","lineNumber":233,"sourceCode":"    let has_target_override = variants.iter().any(|v| v.target.is_some());\n    if has_target_override && mode == Some(\"track\") {\n        bail!(\"target overrides are not supported with mode = \\\"track\\\"\");\n    }\n    if has_target_override && content.is_some() {\n        bail!(\"destination variants with inline content are not supported\");\n    }\n    let implied_source = if has_target_override && source.is_none() {\n        if !variants.iter().all(|v| v.target.is_some()) {\n            bail!(\n                \"destination variants require an explicit source when any variant uses the entry key as its target\"\n            );\n        }\n        Some(logical_source_path(target)?)\n    } else {\n        None\n    };\n    if variants.is_empty() && resolve_target_arg(target).is_relative() {\n        bail!(\"target must be absolute or start with ~/\");\n    }\n    for variant in variants {\n        let destination = variant.target.as_deref().unwrap_or(target);\n        if !variant_target_is_absolute(destination) {\n            bail!(\"variant target must be absolute or start with ~/\");\n        }\n    }\n    Ok(implied_source)\n}\n\nfn logical_source_path(key: &str) -> Result<PathBuf> {\n    let path = file::replace_path(key);\n    if !path.is_relative() {\n        bail!(\n            \"destination variants require an explicit source unless the entry key is a relative source path\"\n        );\n    }\n    let mut relative = PathBuf::new();","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/files.rs#L215-L251","documentation":"Thrown by `validate_file_variants` when a file entry has no variants and its `target` argument resolves to a relative path. File entries must name an absolute destination (or one starting with `~/` for the home directory), because the tool cannot safely place a file at a path relative to an unspecified working directory.","triggerScenarios":"Declaring a file entry without any `[[files.variants]]` whose target (after resolve_target_arg) is relative — e.g. `target = \"dotfiles/zshrc\"` or omitting path-qualifying prefixes — during validate_incoming_files or merge_file_entry.","commonSituations":"Hand-writing config and forgetting the leading `~/` or `/`; environment-specific configs that assume a base directory that the validator does not apply; copy-pasting a source path into the target field.","solutions":["Prefix the target with `~/` to anchor it to the home directory.","Or use a fully absolute path (`/etc/...`, `/usr/local/...`).","If the destination should vary per machine, express it with variants using absolute targets."],"exampleFix":"// before\n[[files]]\nsource = \"zshrc\"\ntarget = \".zshrc\"\n// after\n[[files]]\nsource = \"zshrc\"\ntarget = \"~/.zshrc\"","handlingStrategy":"validation","validationCode":"let t = shellexpand::tilde(entry.target.trim());\nif !entry.target.starts_with(\"~/\") && !Path::new(t.as_ref()).is_absolute() {\n    bail!(\"entry {} target must be absolute or start with ~/\", entry.key);\n}","typeGuard":"fn target_is_absolute(target: &str) -> bool {\n    target.starts_with(\"~/\") || Path::new(target).is_absolute()\n}","tryCatchPattern":null,"preventionTips":["Always anchor file targets with `~/` or `/`.","Never copy a relative source path into the target field.","Add a config lint that checks path absoluteness before apply."],"tags":["config","paths","validation"],"backgroundTag":"invalid-config-value","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}