{"record":{"id":"04c60c9bea37a174","repo":"jdx/mise","slug":"matching-owner-is-present","errorCode":null,"errorMessage":"matching owner is present","messagePattern":"matching owner is present","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":333,"sourceCode":"                \"file\",\n                request.path.as_path(),\n                &mut request.owner,\n                &mut request.group,\n            )\n        })\n        .chain(directories.iter_mut().map(|request| {\n            (\n                \"directory\",\n                request.path.as_path(),\n                &mut request.owner,\n                &mut request.group,\n            )\n        }))\n    {\n        if owner.as_ref().is_some_and(|owner| users.contains(owner)) {\n            warn!(\n                \"ignoring owner '{}' for managed {kind} '{}' because [bootstrap.users] is Linux-only\",\n                owner.as_deref().expect(\"matching owner is present\"),\n                path.display()\n            );\n            *owner = None;\n        }\n        if group.as_ref().is_some_and(|group| groups.contains(group)) {\n            warn!(\n                \"ignoring group '{}' for managed {kind} '{}' because [bootstrap.groups] is Linux-only\",\n                group.as_deref().expect(\"matching group is present\"),\n                path.display()\n            );\n            *group = None;\n        }\n    }\n}\n\npub(crate) fn inspect_requests(\n    files: &mut [ManagedFileRequest],\n    directories: &mut [ManagedDirectoryRequest],","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/managed_files.rs#L315-L351","documentation":"Inside the is_some_and(|owner| users.contains(owner)) branch, owner is known to be Some and contained, so as_deref().expect(\"matching owner is present\") is an invariant assertion. Panicking means the option was concurrently or logically cleared between the check and the deref — a code-structure violation, not a user input problem.","triggerScenarios":"Calling clear_ignored_principals (via ignore_non_linux_account_principals) when the owner Option changed between is_some_and and as_deref — only possible through a refactor that alters the check, or misuse of the matched guard.","commonSituations":"Developers restructuring the warning block and breaking the Some-and-contains pairing; reviewers seeing this panic after such a change.","solutions":["Keep the check-and-deref inside a single if let Some(owner) = owner.as_deref() block filtered by users.contains(owner)","Avoid clearing *owner before logging it"],"exampleFix":"// before\nif owner.as_ref().is_some_and(|owner| users.contains(owner)) {\n    warn!(\"...\", owner.as_deref().expect(\"matching owner is present\"), ...);\n// after\nif let Some(owner_name) = owner.as_deref().filter(|o| users.contains(o)) {\n    warn!(\"...\", owner_name, ...);","handlingStrategy":"type-guard","validationCode":"// check principal before warning\nlet is_ignored = owner.as_deref().map(|o| users.contains(o)).unwrap_or(false);","typeGuard":"fn ignored_owner<'a>(owner: &'a Option<String>, users: &HashSet<String>) -> Option<&'a str> {\n    owner.as_deref().filter(|o| users.contains(*o))\n}","tryCatchPattern":null,"preventionTips":["Use filter/let-else to fuse check and deref in one binding","Never mutate the Option between check and use","Add clippy-driven tests for principal-clearing paths"],"tags":["panic","linux","permissions","invariant","managed-files"],"backgroundTag":"internal-invariant-violation","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"}