{"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":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":1387,"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":1369,"sourceCodeEnd":1405,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/managed_files.rs#L1369-L1405","documentation":"The `mode` field of a managed file/directory must be an octal string no larger than 0o7777 (permission + setuid/setgid/sticky bits). `parse_mode` strips an optional `0o` prefix, parses base-8 (failing earlier with \"mode must be an octal string\"), and rejects values above 0o7777. Note decimal-looking digits 8/9 are caught by the octal parse, not this message.","triggerScenarios":"A [bootstrap.files]/[bootstrap.directories] entry with `mode` whose octal value exceeds 0o7777, e.g. mode = \"77770\", mode = \"0o10000\", or a stray extra digit appended to a valid mode.","commonSituations":"Typo of an extra digit (\"07777\" vs \"7777\" then adding another); pasting a full stat output or decimal permission number into mode; confusing decimal 7777 with octal 0o7777.","solutions":["Correct the mode to a 3-4 digit octal string, e.g. mode = \"0644\" or mode = \"0755\".","Drop any bit above 0o7777 — setuid/setgid/sticky are the only extras allowed on top of rwxrwxrwx.","If you meant a decimal value, convert it to octal first (e.g. decimal 493 = octal 755)."],"exampleFix":"# before\n[bootstrap.files.appconf]\nmode = \"177770\"\n\n# after\n[bootstrap.files.appconf]\nmode = \"0644\"\n","handlingStrategy":"validation","validationCode":"import re\ndef check_mode(m):\n    if m is None: return\n    s = m.removeprefix('0o')\n    if not re.fullmatch(r'[0-7]{3,4}', s) or int(s, 8) > 0o7777:\n        raise ValueError(f\"mode must be an octal string <= 7777, got {m}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Write modes as 3-4 octal digits (\"0644\", \"4755\").","Never paste decimal permission numbers into mode.","Add a config lint that regex-validates mode fields as octal."],"tags":["config","permissions","validation","octal"],"backgroundTag":"value-out-of-range","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"}