gitbutlerapp/gitbutler · error

DefaultTargetNotFound

DefaultTargetNotFound

Error message

there is no default target

What it means

ProjectMeta::target_ref_or_err returns the workspace's default target branch ref, or fails with Code::DefaultTargetNotFound when project metadata has none configured. Nearly every workspace operation (virtual branches, apply/unapply, push) needs the target, so this usually means 'the project is not set up'. Note the code just above: when the configured target ref can no longer be validated, target_ref is actively set to None — a deleted upstream target branch also lands here.

Source

Thrown at crates/but-core/src/ref_metadata.rs:300

    match repo.find_reference(target_ref) {
        Ok(mut target_ref) => {
            if project_meta.target_commit_id.is_none()
                && let Ok(commit) = target_ref.peel_to_commit()
            {
                project_meta.target_commit_id = Some(commit.id);
            }
        }
        Err(_) => project_meta.target_ref = None,
    }
    project_meta
}

impl ProjectMeta {
    /// Return [`Self::target_ref`], or a [`DefaultTargetNotFound`](but_error::Code::DefaultTargetNotFound)
    /// error if no target is configured.
    pub fn target_ref_or_err(&self) -> Result<&gix::refs::FullName> {
        self.target_ref.as_ref().ok_or_else(|| {
            anyhow::anyhow!("there is no default target")
                .context(but_error::Code::DefaultTargetNotFound)
        })
    }

    /// Return [`Self::target_commit_id`], or a [`DefaultTargetNotFound`](but_error::Code::DefaultTargetNotFound)
    /// error if no target commit is known.
    pub fn target_commit_id_or_err(&self) -> Result<gix::ObjectId> {
        self.target_commit_id.ok_or_else(|| {
            anyhow::anyhow!("there is no default target commit")
                .context(but_error::Code::DefaultTargetNotFound)
        })
    }

    /// The name of the remote to push to: [`Self::push_remote`], falling back to the
    /// remote behind [`Self::target_ref`].
    ///
    /// If no configured remote matches the target ref, fall back to the first path component
    /// after `refs/remotes/`, the textual remote name that legacy metadata stored verbatim.

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Set (or re-select) a target branch via project settings / the workspace API, then retry.
  2. If the target branch was deleted upstream, restore it or choose another existing branch as target.
  3. Catch Code::DefaultTargetNotFound and route the user into the target-setup flow instead of showing a generic error.
  4. Confirm afterwards that target_ref_or_err() succeeds.

Example fix

// before
let target = project_meta.target_ref_or_err()?;

// after
let target = match project_meta.target_ref_or_err() {
    Ok(name) => name,
    Err(err) if is_code(&err, &Code::DefaultTargetNotFound) => {
        run_target_setup_flow(&ctx)?; // user picks a target
        ctx.project_meta()?.target_ref_or_err()?
    }
    Err(err) => return Err(err),
};
Defensive patterns

Strategy: try-catch

Validate before calling

let meta = project_meta(&ctx)?;
if meta.target_ref.is_none() {
    // run target setup before any workspace operation
    return setup_target(&ctx);
}

Try / catch

match op_result {
    Err(err) if err.chain().any(|c| c.downcast_ref::<but_error::Code>()
        == Some(&but_error::Code::DefaultTargetNotFound)) => setup_target_flow(),
    other => other,
}?

Prevention

When it happens

Trigger: Any workspace API needing the target branch on a project whose metadata has target_ref = None: brand-new projects before target selection, interrupted setup, or sanitization after the target ref disappeared from the remote.

Common situations: The user deleted the default branch on the host; onboarding abandoned before picking a target; corrupted or very old metadata; switching targets mid-operation.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/e2b07b652df7be37. Report an issue: GitHub.