jdx/mise · error

repos: {}: {reason}

Error message

repos: {}: {reason}

What it means

preflight_statuses rejects RepoState::Conflict entries, whose reason string comes from status_one: (1) `path exists and is not a directory` — a file occupies the target path; (2) `path exists and is not a git repository` — a non-empty directory with no .git; (3) `origin does not match configured url` — the clone's origin identifies a different repository than the configured url. Origin comparison is transport-agnostic: `git@host:path`, `ssh://git@host/path`, and `https://host/path` are equivalent, but a different host, owner/path, non-`git` ssh user, explicit port, or insecure `http://`/`git://` is a conflict.

Source

Thrown at src/system/repos.rs:167

        write!(f, "{}", file::display_path(&self.path))
    }
}

pub fn status(requests: &[RepoRequest]) -> Result<Vec<RepoStatus>> {
    requests.iter().map(status_one).collect()
}

pub fn preflight_statuses(statuses: &[RepoStatus]) -> Result<()> {
    for status in statuses {
        match &status.state {
            RepoState::Dirty => {
                bail!(
                    "repos: {} has local changes; commit, stash, or clean them before bootstrap",
                    status.request
                );
            }
            RepoState::Conflict(reason) => {
                bail!("repos: {}: {reason}", status.request);
            }
            RepoState::Current | RepoState::Missing | RepoState::Differs => {}
        }
    }
    Ok(())
}

/// Apply statuses previously validated with [`preflight_statuses`].
pub(crate) fn apply_statuses(statuses: &[RepoStatus], dry_run: bool) -> Result<()> {
    for status in statuses {
        match &status.state {
            RepoState::Current => {
                info!("repos: {} already current", status.request);
            }
            RepoState::Missing => clone_repo(&status.request, dry_run)?,
            RepoState::Differs => update_repo(&status.request, dry_run)?,
            RepoState::Dirty | RepoState::Conflict(_) => unreachable!("preflighted above"),
        }

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. For a non-directory or non-git path: move or delete it (`mv ~/src/x ~/src/x.bak`) so bootstrap can clone fresh
  2. For an origin mismatch: point the remote at the configured URL with `git -C <repo> remote set-url origin <configured-url>`, or update the config url to the URL you actually use
  3. Keep owner/path identical across transports — `https://github.com/o/r` matches `git@github.com:o/r.git`, but not `git@gitlab.com:o/r.git` or `ssh://git@github.com:2222/o/r.git`

Example fix

# before: origin conflict
$ git -C ~/src/mise remote set-url origin https://github.com/other/mise.git
# after: align the remote with the configured url
$ git -C ~/src/mise remote set-url origin https://github.com/jdx/mise.git
$ mise bootstrap
Defensive patterns

Strategy: validation

Validate before calling

fn origin_matches(path: &Path, configured_url: &str) -> bool {
    let out = std::process::Command::new("git")
        .arg("-C").arg(path)
        .args(["config", "--get", "remote.origin.url"])
        .output();
    matches!(out, Ok(o) if o.status.success() && String::from_utf8_lossy(&o.stdout).trim() == configured_url)
}

// treat the repo as manageable only when the path is a directory containing .git
// and the origin matches (ssh/https equivalents of the same host/path are accepted by mise).

Type guard

fn path_is_clonable_target(path: &Path) -> bool {
    !path.exists() || (path.is_dir() && path.join(".git").exists())
}

Prevention

When it happens

Trigger: A regular file already exists at the repo path; the directory was pre-created with content but no .git; the clone's origin points at a fork, a different host, an ssh alias (`git@github-work:...`), an explicit port, or a userless ssh form while config declares an explicit-user/https URL.

Common situations: Re-cloning a project after forking while config still names upstream; ssh host aliases in ~/.ssh/config vs literal hosts in mise.toml; switching between ssh and https forms of the same repo is fine, switching host or owner is not.

Related errors


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