jdx/mise · error

absent bootstrap user

Error message

absent bootstrap user '{name}' may only set state and remove_home

What it means

When a bootstrap user is declared with state=absent, mise only allows configuring the user's state and remove_home; all other user attributes (shell, comment, uid/gid, groups, system, create_home, move_home, home, etc.) are rejected. This prevents silently configuring properties of a user that will not exist. The check runs during bootstrap plan validation in src/system/accounts.rs.

Solutions

  1. Strip all attribute fields from the user entry, keeping only state (and remove_home if desired).
  2. If you actually want the user configured, remove state="absent" so the fields are meaningful.
  3. Run `mise bootstrap plan` to confirm which fields triggered the rejection.

Example fix

// before
[[bootstrap.users]]
name = "svc"
state = "absent"
shell = "/usr/sbin/nologin"
groups = ["docker"]

// after
[[bootstrap.users]]
name = "svc"
state = "absent"
remove_home = true
Defensive patterns

Strategy: validation

Validate before calling

function validateAbsentUser(user) {
  const allowed = new Set(['name', 'state', 'remove_home']);
  if (user.state === 'absent') {
    const extra = Object.keys(user).filter((k) => !allowed.has(k));
    if (extra.length) throw new Error(`absent user sets fields: ${extra.join(', ')}`);
  }
}

Type guard

function isAbsentOnlyUser(user) {
  return user.state === 'absent' &&
    Object.keys(user).every((k) => ['name', 'state', 'remove_home'].includes(k));
}

Try / catch

try {
  await mise.bootstrap.apply(config);
} catch (e) {
  if (String(e).includes("may only set state and remove_home")) {
    console.error('Prune attribute fields from absent-user entries:', e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Declaring a bootstrap user with state="absent" while also setting any of: shell, comment, uid/gid, system=true, create_home, move_home, home, groups, or exclusive_groups.

Common situations: Reusing one TOML user block for both 'create this user' and 'remove that user' by only flipping state to absent; refactoring a previously-present user entry to absent without pruning its attribute fields; copy-pasting a present-user definition and adding state="absent".

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/8e89f13841b3c347. Report an issue: GitHub.

Appendix: source

Thrown at src/system/accounts.rs:350

        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");
        }
        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

View on GitHub (pinned to 533346cc37)