jdx/mise · error · eyre::Report
[bootstrap.files]." ": source and content are mutually…
Error message
[bootstrap.files]."{}": source and content are mutually exclusive What it means
ManagedFileTomlConfig::try_from-style conversion (from_toml) validates each [bootstrap.files] entry. A managed file may take its bytes either from a source path on disk or from inline content, never both — the converter bails when config.source and config.content are both Some. This keeps provenance unambiguous for rendering and diffing.
Solutions
- Delete the `content` key and keep `source` if the file should be copied/rendered from disk.
- Delete the `source` key and keep `content` for inline file bodies.
- Move one of the two definitions into a separate file entry under a different path if both variants are genuinely needed.
Example fix
# before [bootstrap.files."/etc/motd"] source = "files/motd" content = "Welcome" state = "present" # after [bootstrap.files."/etc/motd"] source = "files/motd" state = "present"
Defensive patterns
Strategy: validation
Validate before calling
// rust
pub struct FileEntry { source: Option<String>, content: Option<String>, state: State }
impl FileEntry {
fn validate(&self) -> Result<(), &'static str> {
if self.source.is_some() && self.content.is_some() {
return Err("source and content are mutually exclusive");
}
Ok(())
}
} Prevention
- Pick one convention per file: templates on disk use source, tiny bodies use content.
- When migrating between source and content, delete the old key in the same edit.
- Run TOML schema validation (with oneOf constraints) in CI.
When it happens
Trigger: Building a ManagedFile config for a path where both `source` and `content` keys are present in the TOML table, with any state value.
Common situations: Migrating a file from inline content to a source template by adding source before deleting content; an editor merge that kept both keys; generated TOML emitting both fields unconditionally.
Related errors
- [bootstrap.files]." ": absent files must not declare source…
- [bootstrap.directories].
- [bootstrap.files]." ": present files require source or…
- managed path ' ' cannot be present while managed ancestor '…
- managed path ' ' ( ) conflicts with ancestor ' ' ( )…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/30e2467a79e5ec5e.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/managed_files.rs:596
}
Ok(())
}
impl ManagedFileRequest {
fn from_toml(
root_config: &Config,
path: PathBuf,
config: ManagedFileTomlConfig,
base: &Path,
origin: ResourceOrigin,
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 = resolve_source_path(base, &source);
Some(fs::read_to_string(&source).wrap_err_with(|| {
format!(
"[bootstrap.files].\"{}\": failed to read source {}",
path.display(),
source.display()
)
})?)
}
(None, Some(content), ManagedState::Present) => Some(content),
(None, None, ManagedState::Present) => bail!(
"[bootstrap.files].\"{}\": present files require source or content",
path.display()View on GitHub (pinned to 533346cc37)