{"record":{"id":"508644c4964af779","repo":"jdx/mise","slug":"matching-group-is-present","errorCode":null,"errorMessage":"matching group is present","messagePattern":"matching group is present","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":341,"sourceCode":"                \"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],\n) -> Result<()> {\n    inspect_paths(files, directories)\n}\n\nfn files_from_config(\n    config: &Config,\n    secrets: &super::secrets::SecretValues,\n) -> Result<Vec<ManagedFileRequest>> {","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/managed_files.rs#L323-L359","documentation":"Same pattern as the owner case: within is_some_and(|group| groups.contains(group)), the group Option is guaranteed Some, and expect(\"matching group is present\") documents that. The panic would indicate the invariant was broken by concurrent modification or a refactor.","triggerScenarios":"clear_ignored_principals warns about a Linux-only [bootstrap.groups] entry when the group Option is not Some-and-contained at deref time — only via code restructuring or shared mutable state.","commonSituations":"Refactors that separate the containment check from the warning log; concurrent mutation of the group field.","solutions":["Use a single binding: if let Some(group_name) = group.as_deref().filter(|g| groups.contains(g))","Log before clearing *group = None"],"exampleFix":"// before\nif group.as_ref().is_some_and(|group| groups.contains(group)) {\n    warn!(\"...\", group.as_deref().expect(\"matching group is present\"), ...);\n// after\nif let Some(group_name) = group.as_deref().filter(|g| groups.contains(g)) {\n    warn!(\"...\", group_name, ...);","handlingStrategy":"type-guard","validationCode":"let is_ignored = group.as_deref().map(|g| groups.contains(g)).unwrap_or(false);","typeGuard":"fn ignored_group<'a>(group: &'a Option<String>, groups: &HashSet<String>) -> Option<&'a str> {\n    group.as_deref().filter(|g| groups.contains(*g))\n}","tryCatchPattern":null,"preventionTips":["Fuse the containment check and the deref into one expression","Log before clearing the Option to None","Keep owner/group clearing logic symmetrical and covered by tests"],"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"}