{"record":{"id":"11b96da1b2f5642d","repo":"jdx/mise","slug":"is-still-not-writable-after-bootstrap","errorCode":null,"errorMessage":"{} is still not writable after bootstrap","messagePattern":"(.+?) is still not writable after bootstrap","errorType":"exception","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/prefix.rs","lineNumber":229,"sourceCode":"        let owner = if cfg!(target_os = \"macos\") {\n            format!(\"{user}:admin\")\n        } else {\n            user\n        };\n        let mut mkdir_dirs: Vec<String> = vec![prefix.to_string_lossy().to_string()];\n        mkdir_dirs.extend(dirs.iter().map(|d| d.display().to_string()));\n        let mkdir_args: Vec<String> = [\"-p\".to_string()].into_iter().chain(mkdir_dirs).collect();\n        let chown_args: Vec<String> = vec![\"-R\".to_string(), owner, prefix.display().to_string()];\n        if dry_run {\n            miseprintln!(\"{}\", sudo::argv(\"mkdir\", &mkdir_args).join(\" \"));\n            miseprintln!(\"{}\", sudo::argv(\"chown\", &chown_args).join(\" \"));\n            return Ok(());\n        }\n        info!(\"creating {} (requires sudo once)\", prefix.display());\n        sudo::run(\"mkdir\", &mkdir_args, &[])?;\n        sudo::run(\"chown\", &chown_args, &[])?;\n        if !writable(&prefix) {\n            bail!(\"{} is still not writable after bootstrap\", prefix.display());\n        }\n    } else if dry_run {\n        // prefix is ours but subdirs are missing — show what a real run\n        // would create (no sudo needed)\n        for dir in &missing_subdirs {\n            miseprintln!(\"mkdir -p {}\", dir.display());\n        }\n    } else {\n        // prefix is ours, just fill in missing subdirs\n        for dir in missing_subdirs {\n            crate::file::create_dir_all(&dir)?;\n        }\n    }\n    Ok(())\n}\n","sourceCodeStart":211,"sourceCodeEnd":245,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/packages/brew/prefix.rs#L211-L245","documentation":"After running sudo mkdir -p and sudo chown -R on the Homebrew prefix, mise re-checks that the prefix is actually writable by the invoking user. If the writability probe still fails, bootstrap could not produce a usable prefix and the error names the path that is stuck. This is an environment-level failure: the chown succeeded as a command but the filesystem still denies writes.","triggerScenarios":"writable(&prefix) returns false immediately after the chown — read-only mounts, root-squashing NFS, SELinux/AppArmor denials, immutable file attributes, or ACLs that override the ownership change.","commonSituations":"Prefix located on an NFS export with root_squash; containers with read-only mounts; hardened systems where even root is constrained by MAC policy; disk mounted ro at runtime.","solutions":["Check mount options for the prefix path (ro, root_squash) and move the prefix to a normal local filesystem","Inspect extended attributes and ACLs (lsattr, getfacl) and clear immutable/read-only flags","Manually create and chown the prefix as root, confirm your user can create a file there, then re-run `mise bootstrap packages apply`"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# pre-flight writability probe mirroring the post-bootstrap check\nPREFIX=\"$HOME/.local/share/mise/brew\"  # or your configured brew prefix\nmkdir -p \"$PREFIX\" 2>/dev/null\ntouch \"$PREFIX/.mise-write-test\" 2>/dev/null || { echo \"$PREFIX not writable (ro mount / root_squash / MAC policy?)\"; exit 1; }\nrm -f \"$PREFIX/.mise-write-test\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the brew prefix on a local, writable filesystem — not NFS with root_squash or read-only mounts","Check lsattr/getfacl on the prefix when chown appears to succeed but writes still fail","On hardened hosts, allow the sudo mkdir/chown in policy before running bootstrap"],"tags":["brew","permissions","sudo","filesystem","prefix"],"backgroundTag":"directory-not-writable","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}