jdx/mise · error

{program} failed with {status}

Error message

{program} failed with {status}

What it means

`run_account_command` locates account-management binaries (`useradd`, `groupadd`, `usermod`, `userdel`, ...) in `/usr/sbin`, `/usr/bin`, `/sbin`, `/bin`, logs the full command at info level, and runs it. If the child exits non-zero, mise bails with the program name and `ExitStatus`; the child's own stderr (printed to the terminal) carries the real diagnosis.

Source

Thrown at src/system/accounts.rs:1012

                    args.push("--remove".to_string());
                }
                args.push(name);
                run_account_command("userdel", &args)
            }
        }
    }
}

fn run_account_command(program: &str, args: &[String]) -> Result<()> {
    let path = ["/usr/sbin", "/usr/bin", "/sbin", "/bin"]
        .iter()
        .map(|dir| PathBuf::from(dir).join(program))
        .find(|path| path.is_file())
        .ok_or_else(|| eyre!("required account command '{program}' was not found"))?;
    info!("$ {} {}", path.display(), args.join(" "));
    let status = Command::new(&path).args(args).status()?;
    if !status.success() {
        bail!("{program} failed with {status}");
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn validates_account_names() {
        assert!(validate_name("user", "mise-cache_1").is_ok());
        assert!(validate_name("user", "1invalid").is_err());
        assert!(validate_name("user", "-invalid").is_err());
        assert!(validate_name("group", "invalid/name").is_err());
        assert!(validate_name("group", &"a".repeat(33)).is_err());
    }

    #[test]

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Find the logged command line (mise prints `$ /usr/sbin/useradd ...` at info level) and run it manually as root to see its stderr.
  2. Fix the reported conflict: drop or change the colliding `uid`/`gid`, close the user's sessions before removal, or declare the missing group in `[bootstrap.groups]`.
  3. Re-run `mise bootstrap accounts apply` (with `--dry-run` first if you want to re-check the plan).

Example fix

# before
[bootstrap.users.builder]
group = "builder"
uid = 1005   # already taken on this host -> useradd exits non-zero

# after
[bootstrap.users.builder]
group = "builder"   # let useradd pick a free uid
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: ensure the requested ids are actually free
fn uid_free(uid: u32) -> bool {
    // read /etc/passwd and check no entry claims uid
    std::fs::read_to_string("/etc/passwd").map(|p| {
        !p.lines().any(|l| l.split(':').nth(2) == Some(&uid.to_string()))
    }).unwrap_or(false)
}

Try / catch

match accounts::apply(&requests, dry_run, yes) {
    Ok(changed) => { /* report */ }
    Err(err) if err.to_string().contains("failed with") => {
        // terminal: program + exit status named; child stderr already printed.
        // Re-run the logged `$ /usr/sbin/<prog> ...` line as root for detail,
        // fix the conflict (uid/gid collision, missing group, logged-in user), retry once.
        return Err(err);
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Converging accounts when the underlying tool fails: `useradd` exits non-zero because the requested `uid` is already in use, the home directory exists, or the primary group is missing; `userdel` fails because the user is logged in; `usermod` fails because a supplementary group does not exist.

Common situations: Hard-coding a uid/gid that collides with an existing account; removing a user with active sessions; referencing a `[bootstrap.groups]` entry that was renamed or ordered after first use; minimal containers missing shadow-utils (then a different error, 'required account command ... was not found', fires instead).

Related errors


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