jdx/mise · error
[bootstrap.files]."{}": source and content are mutually excl
Error message
[bootstrap.files]."{}": source and content are mutually exclusive What it means
ManagedFileRequest::from_toml pattern-matches on (source, content, state) and the (Some, Some, _) arm bails: a `[bootstrap.files]` entry cannot declare both `source` (path to a file whose contents to copy, resolved relative to the config file when relative) and `content` (inline string) (managed_files.rs:447-452). mise cannot know which one wins, so it rejects the ambiguity at parse time, before any templating.
Source
Thrown at src/system/managed_files.rs:442
);
}
Ok(())
}
impl ManagedFileRequest {
fn from_toml(
root_config: &Config,
path: PathBuf,
config: ManagedFileTomlConfig,
base: &Path,
secrets: &super::secrets::SecretValues,
) -> Result<Self> {
let owner = nonempty("owner", config.owner)?;
let group = nonempty("group", config.group)?;
let mode = parse_mode(config.mode.as_deref(), 0o644)?;
let mut content = match (config.source, config.content, config.state) {
(Some(_), Some(_), _) => {
bail!(
"[bootstrap.files].\"{}\": source and content are mutually exclusive",
path.display()
)
}
(Some(source), None, ManagedState::Present) => {
let source = Path::new(&source);
let source = if source.is_absolute() {
source.to_path_buf()
} else {
base.join(source)
};
Some(fs::read_to_string(&source).wrap_err_with(|| {
format!(
"[bootstrap.files].\"{}\": failed to read source {}",
path.display(),
source.display()
)
})?)View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Keep exactly one of source or content: use source for shared/template files on disk, content for short inline strings
- If the entry is state = "absent", remove both keys entirely (see error 610)
- After editing, re-run the bootstrap plan to confirm the entry parses
Example fix
# before [bootstrap.files."/etc/motd"] source = "motd.tmpl" content = "welcome" # after [bootstrap.files."/etc/motd"] content = "welcome"
Defensive patterns
Strategy: validation
Validate before calling
for (path, f) in bootstrap_files(config) {
assert!(!(f.source.is_some() && f.content.is_some()),
"{path}: source and content are mutually exclusive");
} Type guard
// Config struct invariant, checked before handing off to mise
fn is_valid_file_entry(f: &ManagedFileTomlConfig) -> bool {
!(f.source.is_some() && f.content.is_some())
} Prevention
- Pick one authoring style per entry (inline content OR source file) and stick to it
- When toggling entries between content and source, replace rather than add
- Lint TOML: any [bootstrap.files.*] table containing both keys is a CI failure
When it happens
Trigger: A single file entry like `[bootstrap.files."/etc/motd"]` with both `source = "motd.tmpl"` and `content = "hello"` in mise.toml. The check fires for any state, including absent (where the (Some,Some,_) arm precedes the absent-specific arm, so both-fields-plus-absent reports this message first).
Common situations: Iterating on a file's content inline (content = ...) and forgetting to delete an earlier source = ...; merging config snippets from docs/examples that each used a different mechanism; absent-state entries left with stale content/source keys after switching state.
Related errors
- managed system path '{}' is declared as both a file and a di
- managed file paths '{previous}' and '{path}' normalize to th
- managed directory paths '{previous}' and '{path}' normalize
- managed path '{}' cannot be present while managed ancestor '
- [bootstrap.files]."{}": present files require source or cont
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/30e2467a79e5ec5e.
Report an issue: GitHub.