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

  1. Add a groups list alongside exclusive_groups = true.
  2. Remove exclusive_groups (set it to false or delete it) if you do not intend full replacement of memberships.
  3. 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

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


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)