{"record":{"id":"3f3d33ee506acedf","repo":"jdx/mise","slug":"bootstrap-resource-resource-requires-group-g","errorCode":null,"errorMessage":"bootstrap resource '{resource}' requires group '{group}', but that group is absent","messagePattern":"bootstrap resource '(.+?)' requires group '(.+?)', but that group is absent","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/resources.rs","lineNumber":724,"sourceCode":"        return Ok(());\n    }\n    if let Some(owner) = owner {\n        match user_states.get(owner) {\n            Some(super::accounts::AccountState::Present) => {\n                plan.add_dependency(resource, ResourceId::new(\"user\", owner))?;\n            }\n            Some(super::accounts::AccountState::Absent) => bail!(\n                \"bootstrap resource '{resource}' requires owner '{owner}', but that user is absent\"\n            ),\n            None => {}\n        }\n    }\n    if let Some(group) = group {\n        match group_states.get(group) {\n            Some(super::accounts::AccountState::Present) => {\n                plan.add_dependency(resource, ResourceId::new(\"group\", group))?;\n            }\n            Some(super::accounts::AccountState::Absent) => bail!(\n                \"bootstrap resource '{resource}' requires group '{group}', but that group is absent\"\n            ),\n            None => {}\n        }\n    }\n    Ok(())\n}\n\nfn desired_package(request: &super::packages::PackageRequest) -> String {\n    if request.desired == super::packages::PackageDesiredState::Absent {\n        return \"absent\".to_string();\n    }\n    request\n        .version\n        .as_ref()\n        .map(|version| format!(\"installed ({version})\"))\n        .unwrap_or_else(|| \"installed (any version)\".to_string())\n}","sourceCodeStart":706,"sourceCodeEnd":742,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/resources.rs#L706-L742","documentation":"Mirror of the owner check: a bootstrap resource declares a group, and group planning resolved it to AccountState::Absent. The planner refuses to depend on a group that will not exist after the plan runs.","triggerScenarios":"Calling plan with a bootstrap resource whose group is set to a group name for which a group resource exists but is declared Absent.","commonSituations":"Deleting a legacy group while files/directories still declare it as their group; layered configs disagree about the group's state; a group rename not propagated to resource definitions.","solutions":["Mark the group Present (or remove its Absent declaration)","Reassign the resource's group to an existing Present group","Remove the group field if the default group suffices"],"exampleFix":"// before\ngroup(\"app-team\", state: \"absent\")\ndirectory(group: \"app-team\")\n// after\ndirectory(group: \"app-new-team\")","handlingStrategy":"validation","validationCode":"const groups = new Map(accountResources.filter(r => r.kind === 'group').map(r => [r.name, r.state]));\nfor (const res of resources) if (res.group && groups.get(res.group) === 'absent') throw new Error(`${res.id}: group ${res.group} is declared absent`);","typeGuard":"function groupExists(res, groups) { return !res.group || groups.get(res.group) === 'present'; }","tryCatchPattern":"try { plan = planner.plan(); } catch (e) { if (String(e).includes('requires group') && e.message.includes('is absent')) { reassignGroup(config); } else throw e; }","preventionTips":["Audit group references before deleting a group resource","Keep group membership/ownership in the same config file as the group declaration","Rename groups atomically: create the new one and update references before removing the old"],"tags":["accounts","groups","bootstrap"],"backgroundTag":"missing-dependency","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"}