jdx/mise · error
refusing unsafe change to bootstrap user
Error message
refusing unsafe change to bootstrap user '{}'; inspect `mise bootstrap plan` What it means
When applying bootstrap changes, if the computed plan for a user yields ResourceAction::Unknown, mise refuses to proceed rather than guess at a destructive change. 'Unknown' means the live system state could not be reconciled with the declaration (e.g. ambiguous user state), so the safe behavior is to bail and ask the operator to inspect the plan.
Solutions
- Run `mise bootstrap plan` and read the reported action for the offending user.
- Reconcile the live account state manually (userdel/usermod) so the plan becomes Create/Remove/Noop.
- Align the declaration (state and attributes) with the actual system state, then re-apply.
Defensive patterns
Strategy: try-catch
Validate before calling
const plan = await mise.bootstrap.plan(config);
const unsafe = plan.users.filter((u) => u.action === 'unknown');
if (unsafe.length) throw new Error(`Unsafe plan for users: ${unsafe.map((u) => u.name).join(', ')}`); Try / catch
try {
await mise.bootstrap.apply(config);
} catch (e) {
if (String(e).includes('refusing unsafe change to bootstrap user')) {
console.error('Inspect `mise bootstrap plan`, reconcile the live account, then retry.');
} else throw e;
} Prevention
- Always run `mise bootstrap plan` before apply.
- Avoid hand-editing /etc/passwd on hosts managed by bootstrap.
- Re-run plan after any manual account changes.
When it happens
Trigger: Running `mise bootstrap apply` (or similar) when a declared user's computed plan action is Unknown — typically due to inconsistent or unverifiable live system state for that account.
Common situations: Manual edits to /etc/passwd leaving a user in a state mise cannot classify; a user declared absent but detected present with unmanaged attributes; partially failed prior bootstrap runs.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- bootstrap plan contains resources with unknown state
- absent bootstrap group
- absent bootstrap user
- bootstrap_command left multiple
- bootstrap_command left multiple unchanged mise executables…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/eee6d32e28fd8a06.
Report an issue: GitHub.
Appendix: 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 533346cc37)