{"record":{"id":"17ba3350627d41f0","repo":"jdx/mise","slug":"managed-file-parent-does-not-exist","errorCode":null,"errorMessage":"managed file parent does not exist: {}","messagePattern":"managed file parent does not exist: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":1361,"sourceCode":"fn write_file(\n    path: &Path,\n    content: &[u8],\n    owner: Option<&str>,\n    group: Option<&str>,\n    mode: u32,\n    replace: bool,\n) -> Result<()> {\n    let parent = path\n        .parent()\n        .ok_or_else(|| eyre!(\"managed file has no parent: {}\", path.display()))?;\n    match fs::metadata(parent) {\n        Ok(metadata) if metadata.is_dir() => {}\n        Ok(_) => bail!(\n            \"managed file parent is not a directory: {}\",\n            parent.display()\n        ),\n        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {\n            bail!(\"managed file parent does not exist: {}\", parent.display())\n        }\n        Err(error) => return Err(error.into()),\n    }\n    // Prepare the complete replacement before mutating the destination. In\n    // particular, a metadata permission error must leave the old path intact.\n    let mut temporary = tempfile::NamedTempFile::new_in(parent)?;\n    temporary.write_all(content)?;\n    set_metadata(temporary.path(), owner, group, mode)?;\n    temporary.as_file_mut().sync_all()?;\n    match fs::symlink_metadata(path) {\n        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}\n        Err(error) => return Err(error.into()),\n        Ok(metadata) if metadata.file_type().is_file() => {}\n        Ok(_) if !replace => {\n            bail!(\"refusing to replace non-file path: {}\", path.display())\n        }\n        Ok(metadata) if metadata.file_type().is_dir() => {\n            fs::remove_dir(path).wrap_err_with(|| {","sourceCodeStart":1343,"sourceCodeEnd":1379,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/managed_files.rs#L1343-L1379","documentation":"write_file() requires the parent directory to exist - mise does not implicitly mkdir -p for managed files. If fs::metadata(parent) returns NotFound, the write is refused before any mutation happens, leaving the old state intact.","triggerScenarios":"Declaring [bootstrap.files] \"/opt/app/settings.conf\" when /opt/app (or an ancestor) does not exist and no matching [bootstrap.directories] entry creates it.","commonSituations":"Fresh machine where the application directory was never created; assuming managed files auto-create their parent directories.","solutions":["Add a [bootstrap.directories] entry for the parent so the run creates it before the file","Or pre-create the directory yourself: sudo mkdir -p /opt/app"],"exampleFix":"# before\n[bootstrap.files]\n\"/opt/app/settings.conf\" = { content = \"...\" }\n\n# after\n[bootstrap.directories]\n\"/opt/app\" = { owner = \"app\", mode = \"0755\" }\n[bootstrap.files]\n\"/opt/app/settings.conf\" = { content = \"...\", mode = \"0644\" }","handlingStrategy":"validation","validationCode":"let parent = path.parent().ok_or_else(|| eyre::eyre!(\"no parent\"))?;\nif !parent.exists() {\n    return Err(eyre::eyre!(\"managed file parent does not exist: {}\", parent.display()));\n}","typeGuard":"fn parent_exists(path: &std::path::Path) -> bool {\n    path.parent().map(|p| p.exists()).unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Declare parent directories in [bootstrap.directories] alongside nested files","On fresh machines, run the full bootstrap rather than partial applies"],"tags":["filesystem","missing-directory","config","managed-files"],"backgroundTag":"missing-parent-directory","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}