jdx/mise · error

present bootstrap user '{name}' requires a primary group

Error message

present bootstrap user '{name}' requires a primary group

What it means

UserRequest::from_toml requires that a bootstrap user with state = "present" declares a primary group (config.group). A POSIX user cannot be created without a primary group, and mise does not guess defaults (no implicit 'create a same-name group'), so the config is rejected at parse time with the user's name in the message.

Source

Thrown at src/system/accounts.rs:333

                gid: self.gid,
                system: self.system,
            })),
            ResourceAction::Update => Ok(Some(AccountAction::UpdateGroup {
                name: self.name.clone(),
                gid: self.gid.expect("group update requires a desired gid"),
            })),
            ResourceAction::Remove => Ok(Some(AccountAction::RemoveGroup {
                name: self.name.clone(),
            })),
        }
    }
}

impl UserRequest {
    fn from_toml(name: String, config: UserTomlConfig) -> Result<Self> {
        validate_name("user", &name)?;
        if config.state == AccountState::Present && config.group.is_none() {
            bail!("present bootstrap user '{name}' requires a primary group");
        }
        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");
        }

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Add group = "<name>" (or an existing group) to the present user entry.
  2. If that group does not exist yet, also declare it under [bootstrap.groups.<name>] or reference a group that already exists on the host.
  3. Re-run `mise bootstrap plan` to confirm validation passes.

Example fix

# before
[bootstrap.users.jenkins]
state = "present"
# after
[bootstrap.users.jenkins]
state = "present"
group = "jenkins"

[bootstrap.groups.jenkins]
state = "present"
Defensive patterns

Strategy: validation

Validate before calling

python3 - <<'EOF'
import sys, tomllib
cfg = tomllib.load(open('mise.toml','rb'))
for name, u in cfg.get('bootstrap', {}).get('users', {}).items():
    if u.get('state') == 'present' and 'group' not in u:
        sys.exit(f"present user '{name}' requires a primary group")
EOF

Type guard

def present_user_has_group(u: dict) -> bool:
    return 'group' in u if u.get('state') == 'present' else True

Prevention

When it happens

Trigger: A [bootstrap.users.<name>] table with state = "present" and no group = "..." key, loaded during `mise bootstrap plan`/`apply` or any account-request build.

Common situations: Copy-pasting an absent-user template and flipping state to present; assuming mise auto-creates a matching group; migrating from a system that lets the primary group default.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/7c4ca4a8633ed5fd. Report an issue: GitHub.