jdx/mise · error
absent bootstrap user '{name}' may only set state and remove
Error message
absent bootstrap user '{name}' may only set state and remove_home What it means
UserRequest::from_toml enforces that an absent user (state = "absent") may configure nothing except state and remove_home. If any of uid, group, groups, exclusive_groups, home, shell, comment, system, create_home, or move_home is set on an absent user, parsing bails. Deletion requests are name-only by design, so leftover creation attributes are treated as a config error rather than silently ignored.
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
.commentView on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Strip the absent user's table down to state = "absent" (plus remove_home = true only if the home directory should be deleted).
- If the attributes are needed, the user should be state = "present" instead.
- Re-run `mise bootstrap plan` to verify.
Example fix
# before [bootstrap.users.oldsvc] state = "absent" uid = 900 shell = "/usr/sbin/nologin" # after [bootstrap.users.oldsvc] state = "absent" remove_home = true
Defensive patterns
Strategy: validation
Validate before calling
python3 - <<'EOF'
import sys, tomllib
ABSENT_OK = {'state', 'remove_home'}
cfg = tomllib.load(open('mise.toml','rb'))
for name, u in cfg.get('bootstrap', {}).get('users', {}).items():
if u.get('state') == 'absent' and set(u) - ABSENT_OK:
extra = sorted(set(u) - ABSENT_OK)
sys.exit(f"absent user '{name}' sets disallowed keys: {extra}")
EOF Type guard
ABSENT_ALLOWED = {'state', 'remove_home'}
def absent_user_is_name_only(u: dict) -> bool:
return set(u) <= ABSENT_ALLOWED if u.get('state') == 'absent' else True Prevention
- Author absent-user entries from scratch rather than editing present ones.
- Keep deprovisioning and provisioning in separate config files.
- Run `mise bootstrap plan` as a lint step.
When it happens
Trigger: A [bootstrap.users.<name>] table with state = "absent" that also sets e.g. uid = 1200, shell = "/bin/bash", or groups = [...], while `mise bootstrap` loads the config.
Common situations: Converting a fully-specified present user to absent by changing only the state field; deprovisioning configs generated from provisioning templates; merging config layers where an absent entry inherits extra keys.
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
- present bootstrap user '{name}' requires a primary group
- present bootstrap user '{name}' must not set remove_home
- absent bootstrap group '{name}' must not set gid or system
- bootstrap user '{name}' sets exclusive_groups without groups
- bootstrap user '{name}' sets move_home without home
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/8e89f13841b3c347.
Report an issue: GitHub.