{"record":{"id":"28892a6d63b908a7","repo":"jdx/mise","slug":"bootstrap-files-present-files-require-sour","errorCode":null,"errorMessage":"[bootstrap.files].\"{}\": present files require source or content","messagePattern":"\\[bootstrap\\.files\\]\\.\"(.+?)\": present files require source or content","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":463,"sourceCode":"                )\n            }\n            (Some(source), None, ManagedState::Present) => {\n                let source = Path::new(&source);\n                let source = if source.is_absolute() {\n                    source.to_path_buf()\n                } else {\n                    base.join(source)\n                };\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()\n            ),\n            (None, None, ManagedState::Absent) => None,\n            (_, _, ManagedState::Absent) => bail!(\n                \"[bootstrap.files].\\\"{}\\\": absent files must not declare source or content\",\n                path.display()\n            ),\n        };\n        if config.template {\n            let rendered = content\n                .as_deref()\n                .map(|content| secrets.render(root_config, content, base, &path))\n                .transpose()\n                .wrap_err_with(|| {\n                    format!(\n                        \"[bootstrap.files].\\\"{}\\\": failed to render template\",\n                        path.display()","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/managed_files.rs#L445-L481","documentation":"The (None, None, Present) arm of from_toml's match: a `[bootstrap.files]` entry with `state = \"present\"` (the default state) declared neither `source` nor `content`, so there is nothing to write (managed_files.rs:459-462). Present files need material; absent files (None,None,Absent) are the valid no-key form.","triggerScenarios":"`[bootstrap.files.\"/etc/app.env\"]` with only owner/group/mode and no source/content; or an entry where state was flipped from \"absent\" to \"present\" without adding material. Note state defaults to present, so a bare entry with just metadata triggers this.","commonSituations":"Starting an entry as a metadata skeleton intending to add content later; deleting the content key while debugging templating; YAML/TOML indentation mistakes that detach the content key from its table so it's parsed as absent.","solutions":["Add `content = \"...\"` with the inline file body, or `source = \"path/to/file\"` (absolute, or relative to the config file's directory) supplying the body","If the file shouldn't be managed as present, set `state = \"absent\"` and keep no content keys","Verify the key actually sits inside the right `[bootstrap.files.\"<path>\"]` table (no stray blank line turning it into a new table)"],"exampleFix":"# before\n[bootstrap.files.\"/etc/app.env\"]\nowner = \"root\"\nmode = \"0644\"\n\n# after\n[bootstrap.files.\"/etc/app.env\"]\nowner = \"root\"\nmode = \"0644\"\ncontent = \"KEY=value\\n\"","handlingStrategy":"validation","validationCode":"for (path, f) in bootstrap_files(config) {\n    if f.state.unwrap_or(Present) == Present {\n        assert!(f.source.is_some() || f.content.is_some(),\n            \"{path}: present file needs source or content\");\n    }\n}","typeGuard":"fn is_complete_file_entry(f: &ManagedFileTomlConfig) -> bool {\n    matches!(f.state, None | Some(Present)) && f.source.is_none() && f.content.is_none() ^ true\n        && (f.source.is_some() || f.content.is_some() || f.state == Some(Absent))\n}","tryCatchPattern":null,"preventionTips":["Remember state defaults to present — a bare metadata-only entry is invalid","Use a TOML schema/JSON-schema check in CI that marks source xor content required for present files","Watch table boundaries: a blank line can silently detach your content key"],"tags":["bootstrap","config-validation","missing-field","managed-files"],"backgroundTag":"missing-required-config-field","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}