{"record":{"id":"e28f064fcfe65906","repo":"jdx/mise","slug":"mode-must-be-between-0000-and-7777","errorCode":null,"errorMessage":"mode must be between 0000 and 7777","messagePattern":"mode must be between 0000 and 7777","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":1210,"sourceCode":"fn validate_privileged_target(path: &Path) -> Result<PathBuf> {\n    if !path.is_absolute() {\n        bail!(\"managed system path must be absolute: {}\", path.display());\n    }\n    let path = path.absolutize()?.to_path_buf();\n    if path == Path::new(\"/\") {\n        bail!(\"refusing to manage the filesystem root\");\n    }\n    Ok(path)\n}\n\nfn parse_mode(mode: Option<&str>, default: u32) -> Result<u32> {\n    let Some(mode) = mode else {\n        return Ok(default);\n    };\n    let mode = mode.strip_prefix(\"0o\").unwrap_or(mode);\n    let parsed = u32::from_str_radix(mode, 8).wrap_err(\"mode must be an octal string\")?;\n    if parsed > 0o7777 {\n        bail!(\"mode must be between 0000 and 7777\");\n    }\n    Ok(parsed)\n}\n\nfn nonempty(field: &str, value: Option<String>) -> Result<Option<String>> {\n    match value {\n        Some(value) if value.trim().is_empty() => bail!(\"{field} must not be empty\"),\n        Some(value) => Ok(Some(value)),\n        None => Ok(None),\n    }\n}\n\nfn desired_metadata(kind: &str, mode: u32, owner: Option<&str>, group: Option<&str>) -> String {\n    let mut desired = format!(\"{kind} mode {mode:04o}\");\n    if let Some(owner) = owner {\n        desired.push_str(&format!(\" owner {owner}\"));\n    }\n    if let Some(group) = group {","sourceCodeStart":1192,"sourceCodeEnd":1228,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/managed_files.rs#L1192-L1228","documentation":"The mode field of managed files/directories is parsed by parse_mode(): optional \"0o\" prefix, then strict octal via u32::from_str_radix(_, 8), and the value must be <= 0o7777 (the 12-bit permission mask). Non-octal digits fail earlier with the wrapped \"mode must be an octal string\" error; this specific bail means the number parsed fine but exceeds 7777.","triggerScenarios":"mode = \"0o10000\" or any octal value above 0o7777; copy-pasting a full st_mode value that includes file-type bits (e.g. \"100644\" parses as octal but overflows the mask).","commonSituations":"Pasting stat/st_mode output into config; assuming mode is decimal; adding an extra digit to \"0644\".","solutions":["Use a 3-4 digit octal permission string: \"0644\", \"0755\", \"0600\"","If copying from st_mode, keep only the low 12 permission bits"],"exampleFix":"# before\n[bootstrap.files]\n\"/etc/app/app.conf\" = { content = \"...\", mode = \"100644\" }\n\n# after\n[bootstrap.files]\n\"/etc/app/app.conf\" = { content = \"...\", mode = \"0644\" }","handlingStrategy":"validation","validationCode":"let m = mode.strip_prefix(\"0o\").unwrap_or(mode);\nlet parsed = u32::from_str_radix(m, 8).wrap_err(\"mode must be an octal string\")?;\nif parsed > 0o7777 {\n    return Err(eyre::eyre!(\"mode must be between 0000 and 7777\"));\n}","typeGuard":"fn is_valid_mode_string(mode: &str) -> bool {\n    let m = mode.strip_prefix(\"0o\").unwrap_or(mode);\n    !m.is_empty()\n        && m.chars().all(|c| ('0'..='7').contains(&c))\n        && u32::from_str_radix(m, 8).map(|v| v <= 0o7777).unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Author modes as 4-digit octal with a leading zero (\"0644\")","Never paste raw st_mode values that include file-type bits"],"tags":["validation","permissions","octal","config","managed-files"],"backgroundTag":"invalid-file-mode","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}