gitbutlerapp/gitbutler · error

Couldn't find remote refspecs that would match

Error message

Couldn't find remote refspecs that would match {}

What it means

After confirming the remote-tracking ref exists, local_tracking_branch asks gix for the local branch that the tracking ref maps to via the remote's fetch refspecs. When no refspec matches, there is no local branch to return and the function bails.

Solutions

  1. Add the standard wildcard fetch refspec: `git config remote.<name>.fetch "+refs/heads/*:refs/remotes/<name>/*"`
  2. Create the tracking ref via a normal `git fetch <remote>` so refspec-based mapping exists
  3. Use a tracking ref that belongs to a properly configured remote

Example fix

// before (config)
[remote "origin"]
  url = ...
  push = +refs/heads/*:refs/heads/*
// after (config)
[remote "origin"]
  url = ...
  fetch = +refs/heads/*:refs/remotes/origin/*
Defensive patterns

Strategy: validation

Validate before calling

fn refspec_covers(repo: &gix::Repository, tracking: &gix::refs::FullNameRef) -> anyhow::Result<bool> {
    Ok(repo.upstream_branch_and_remote_for_tracking_branch(tracking)?.is_some())
}

Try / catch

match result {
    Err(e) if e.to_string().contains("Couldn't find remote refspecs") => {
        eprintln!("add remote.<name>.fetch = +refs/heads/*:refs/remotes/<name>/*");
        anyhow::bail!(e);
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling local_tracking_branch with an existing remote-tracking ref whose remote config lacks a matching fetch refspec, so upstream_branch_and_remote_for_tracking_branch returns None.

Common situations: Manually created tracking refs (e.g. via `git update-ref refs/remotes/upstream/x`) with no corresponding remote fetch refspec; remotes configured only with push refspecs.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/54208004c43415c5. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-workspace/src/branch/mod.rs:605

/// Return the local tracking branch of `remote_tracking_ref`, creating it at the remote-tracking
/// commit with tracking configuration if it doesn't exist yet, like `git checkout <name>` does.
///
/// An existing local tracking branch is returned as is, even if it diverged from the remote.
pub fn local_tracking_branch(
    repo: &gix::Repository,
    remote_tracking_ref: &gix::refs::FullNameRef,
) -> anyhow::Result<gix::refs::FullName> {
    // Symbolic ones, `origin/HEAD` say, would make a local branch of the name they point through.
    if try_find_validated_ref(repo, remote_tracking_ref, "check out")?.is_none() {
        anyhow::bail!(
            "Remote-tracking branch {} does not exist",
            remote_tracking_ref.as_bstr()
        );
    }
    let Some((local_tracking_ref, _remote)) =
        repo.upstream_branch_and_remote_for_tracking_branch(remote_tracking_ref)?
    else {
        anyhow::bail!(
            "Couldn't find remote refspecs that would match {}",
            remote_tracking_ref.as_bstr()
        );
    };
    if repo
        .try_find_reference(local_tracking_ref.as_ref())?
        .is_some()
    {
        return Ok(local_tracking_ref);
    }

    let (config, commit_id) =
        setup_local_tracking_configuration(repo, local_tracking_ref.as_ref(), remote_tracking_ref)?;
    // The reference first, as git does: should it fail, the config transaction drops unwritten.
    repo.reference(
        local_tracking_ref.as_ref(),
        commit_id,
        gix::refs::transaction::PreviousValue::MustNotExist,

View on GitHub (pinned to 58e5313667)