jdx/mise · error

refusing unsafe change to bootstrap user '{}'; inspect `mise

Error message

refusing unsafe change to bootstrap user '{}'; inspect `mise bootstrap plan`

What it means

UserRequest::action() turns the computed plan into an action; if the plan is ResourceAction::Unknown — the inspected current user state cannot be reconciled with the desired state safely (e.g. desired uid is already taken by another user, or inspected fields conflict in a way with no safe usermod transition) — mise refuses to perform any privileged change and points you at `mise bootstrap plan` for the details. Same deliberate safety stop as the group variant.

Source

Thrown at src/system/accounts.rs:546

                groups.iter().cloned().collect::<Vec<_>>().join(",")
            ));
        }
        if let Some(home) = &self.home {
            parts.push(format!("home {}", home.display()));
        }
        if let Some(shell) = &self.shell {
            parts.push(format!("shell {}", shell.display()));
        }
        if let Some(comment) = &self.comment {
            parts.push(format!("comment {comment}"));
        }
        parts.join("; ")
    }

    fn action(&self) -> Result<Option<AccountAction>> {
        match self.plan().action {
            ResourceAction::Noop => Ok(None),
            ResourceAction::Unknown => bail!(
                "refusing unsafe change to bootstrap user '{}'; inspect `mise bootstrap plan`",
                self.name
            ),
            ResourceAction::Create => Ok(Some(AccountAction::CreateUser {
                name: self.name.clone(),
                uid: self.uid,
                group: self
                    .group
                    .clone()
                    .expect("present user has a primary group"),
                groups: self
                    .groups
                    .as_ref()
                    .map(|groups| groups.iter().cloned().collect())
                    .unwrap_or_default(),
                home: self.home.clone(),
                shell: self.shell.clone(),
                comment: self.comment.clone(),

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Run `mise bootstrap plan` and read the diff for the named user.
  2. Resolve uid conflicts: pick a free uid in config, or re-uid/remove the conflicting user manually first.
  3. Align or drop conflicting fields (home/shell/groups) until the plan shows create/update/remove instead of Unknown.
  4. Only then run `mise bootstrap apply`.

Example fix

# before: uid 1100 already owned by user 'oldci'
[bootstrap.users.ci]
state = "present"
group = "ci"
uid = 1100
# after
[bootstrap.users.ci]
state = "present"
group = "ci"
uid = 1150
Defensive patterns

Strategy: validation

Validate before calling

# gate apply on a clean plan
out=$(mise bootstrap plan)
if grep -q 'refusing unsafe change' <<<"$out"; then
  echo "$out" >&2; exit 1
fi
mise bootstrap apply

Try / catch

Hard stop on this bail: parse the user name from the message, run `mise bootstrap plan`, resolve the uid/state collision (pick a free uid or reconcile the user manually), then re-plan. Never auto-retry apply unchanged.

Prevention

When it happens

Trigger: Bootstrap apply where a user's plan resolves to Unknown: uid collisions (desired uid owned by a different username), drifted home/shell/uid state that fits no safe transition, or login-name conflicts. `mise bootstrap plan` shows the Unknown action and the current-vs-desired diff for the named user.

Common situations: Reusing a uid from a removed service account; importing servers whose users drifted from the declared config; uid renumbering during consolidation; running apply on a host never inspected with plan first.

Related errors


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