{"record":{"id":"30e2467a79e5ec5e","repo":"jdx/mise","slug":"bootstrap-files-source-and-content-are-mut","errorCode":null,"errorMessage":"[bootstrap.files].\"{}\": source and content are mutually exclusive","messagePattern":"\\[bootstrap\\.files\\]\\.\"(.+?)\": source and content are mutually exclusive","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":596,"sourceCode":"    }\n    Ok(())\n}\n\nimpl ManagedFileRequest {\n    fn from_toml(\n        root_config: &Config,\n        path: PathBuf,\n        config: ManagedFileTomlConfig,\n        base: &Path,\n        origin: ResourceOrigin,\n        secrets: &super::secrets::SecretValues,\n    ) -> Result<Self> {\n        let owner = nonempty(\"owner\", config.owner)?;\n        let group = nonempty(\"group\", config.group)?;\n        let mode = parse_mode(config.mode.as_deref(), 0o644)?;\n        let mut content = match (config.source, config.content, config.state) {\n            (Some(_), Some(_), _) => {\n                bail!(\n                    \"[bootstrap.files].\\\"{}\\\": source and content are mutually exclusive\",\n                    path.display()\n                )\n            }\n            (Some(source), None, ManagedState::Present) => {\n                let source = resolve_source_path(base, &source);\n                Some(fs::read_to_string(&source).wrap_err_with(|| {\n                    format!(\n                        \"[bootstrap.files].\\\"{}\\\": failed to read source {}\",\n                        path.display(),\n                        source.display()\n                    )\n                })?)\n            }\n            (None, Some(content), ManagedState::Present) => Some(content),\n            (None, None, ManagedState::Present) => bail!(\n                \"[bootstrap.files].\\\"{}\\\": present files require source or content\",\n                path.display()","sourceCodeStart":578,"sourceCodeEnd":614,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/managed_files.rs#L578-L614","documentation":"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.","triggerScenarios":"Building a ManagedFile config for a path where both `source` and `content` keys are present in the TOML table, with any state value.","commonSituations":"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.","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."],"exampleFix":"# before\n[bootstrap.files.\"/etc/motd\"]\nsource = \"files/motd\"\ncontent = \"Welcome\"\nstate = \"present\"\n\n# after\n[bootstrap.files.\"/etc/motd\"]\nsource = \"files/motd\"\nstate = \"present\"","handlingStrategy":"validation","validationCode":"// rust\npub struct FileEntry { source: Option<String>, content: Option<String>, state: State }\nimpl FileEntry {\n    fn validate(&self) -> Result<(), &'static str> {\n        if self.source.is_some() && self.content.is_some() {\n            return Err(\"source and content are mutually exclusive\");\n        }\n        Ok(())\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["config-validation","managed-files","mutually-exclusive"],"backgroundTag":"mutually-exclusive-options","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"}