jdx/mise · error
bootstrap user ' ' sets exclusive_groups without groups
Error message
bootstrap user '{name}' sets exclusive_groups without groups What it means
exclusive_groups declares that the user's group memberships fully replace (not merge with) existing memberships. It is meaningless without a groups list, so mise rejects exclusive_groups=true when groups is unset. This catches configs that would either do nothing or ambiguously imply exclusive control over an empty membership set.
Solutions
- Add a groups list alongside exclusive_groups = true.
- Remove exclusive_groups (set it to false or delete it) if you do not intend full replacement of memberships.
- Run `mise bootstrap plan` to review the intended group changes before re-running.
Example fix
// before [[bootstrap.users]] name = "deploy" exclusive_groups = true // after [[bootstrap.users]] name = "deploy" exclusive_groups = true groups = ["deploy", "docker"]
Defensive patterns
Strategy: validation
Validate before calling
function validateExclusiveGroups(user) {
if (user.exclusive_groups && !Array.isArray(user.groups)) {
throw new Error(`user '${user.name}': exclusive_groups requires a groups list`);
}
} Type guard
function hasGroupsWhenExclusive(user) {
return !user.exclusive_groups || Array.isArray(user.groups) && user.groups.length > 0;
} Try / catch
try {
await mise.bootstrap.apply(config);
} catch (e) {
if (String(e).includes('exclusive_groups without groups')) {
console.error('Add a groups list or drop exclusive_groups:', e.message);
} else throw e;
} Prevention
- Always pair exclusive_groups with an explicit groups array.
- Schema-validate bootstrap TOML before applying.
- Review `mise bootstrap plan` diff to confirm replacement memberships are intended.
When it happens
Trigger: Setting exclusive_groups = true on a bootstrap user while omitting the groups field.
Common situations: Copy-pasting a user entry and deleting the groups list while leaving exclusive_groups enabled; converting an existing user to exclusive management but forgetting to enumerate the target groups.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- absent bootstrap group
- absent bootstrap user
- bootstrap resource ' ' requires group ' ', but that group…
- bootstrap user ' ' sets move_home without home
- bootstrap user ' ' requires group ' ', but that group is…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/5246644b0b3a251d.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/accounts.rs:353
if config.state == AccountState::Present && config.remove_home {
bail!("present bootstrap user '{name}' must not set remove_home");
}
if config.state == AccountState::Absent
&& (config.uid.is_some()
|| config.group.is_some()
|| config.groups.is_some()
|| config.exclusive_groups
|| config.home.is_some()
|| config.shell.is_some()
|| config.comment.is_some()
|| config.system
|| config.create_home.is_some()
|| config.move_home)
{
bail!("absent bootstrap user '{name}' may only set state and remove_home");
}
if config.exclusive_groups && config.groups.is_none() {
bail!("bootstrap user '{name}' sets exclusive_groups without groups");
}
if config.move_home && config.home.is_none() {
bail!("bootstrap user '{name}' sets move_home without home");
}
if let Some(group) = &config.group {
validate_name("group", group)?;
}
if let Some(path) = &config.home {
validate_account_path(&name, "home", path)?;
}
if let Some(path) = &config.shell {
validate_account_path(&name, "shell", path)?;
}
if config
.comment
.as_ref()
.is_some_and(|comment| comment.contains([':', '\n', '\r']))
{View on GitHub (pinned to 533346cc37)