gitbutlerapp/gitbutler · error
targetRef in project_meta.toml is not a remote-tracking bran
Error message
targetRef in project_meta.toml is not a remote-tracking branch
What it means
On snapshot restore, `ProjectMeta` is rebuilt from the stored `project_meta.toml`; a `targetRef` must be a remote-tracking branch (a ref under `refs/remotes/`). A ref name in any other category — local branch, tag, or other — is rejected so a bogus target can never be restored into the project.
Source
Thrown at crates/gitbutler-oplog/src/oplog.rs:97
target_ref: meta.target_ref.as_ref().map(ToString::to_string),
target_commit_id: target_commit_id.to_string(),
push_remote: meta.push_remote.clone(),
})
}
}
impl TryFrom<SnapshotProjectMeta> for ProjectMeta {
type Error = anyhow::Error;
fn try_from(meta: SnapshotProjectMeta) -> Result<Self> {
let target_ref = meta
.target_ref
.map(|name| {
let name: gix::refs::FullName = name
.try_into()
.context("invalid targetRef in project_meta.toml")?;
if name.category() != Some(gix::refs::Category::RemoteBranch) {
bail!("targetRef in project_meta.toml is not a remote-tracking branch");
}
Ok(name)
})
.transpose()?;
let target_commit_id = gix::ObjectId::from_str(&meta.target_commit_id)
.context("invalid targetCommitId in project_meta.toml")?;
if target_commit_id.is_null() {
bail!("targetCommitId in project_meta.toml is null");
}
Ok(Self {
target_ref,
target_commit_id: Some(target_commit_id),
push_remote: meta.push_remote,
})
}
}
/// The Oplog allows for crating snapshots of the current state of the project as well as restoring to a previous snapshot.View on GitHub (pinned to caf1f223d3)
Solutions
- Fix the snapshot's targetRef to a valid remote-tracking ref such as `refs/remotes/origin/main` and retry the restore
- Restore from an earlier, consistent snapshot entry instead
- Recreate the state manually (reselect the target branch, re-apply changes) if the snapshot cannot be repaired
Defensive patterns
Strategy: validation
Validate before calling
let name: gix::refs::FullName = stored_target_ref.parse()?;
if name.category() != Some(gix::refs::Category::RemoteBranch) {
return Err(anyhow::anyhow!("refusing snapshot with non-remote-tracking targetRef {name}"));
} Type guard
fn is_remote_tracking(ref_name: &gix::refs::FullName) -> bool {
ref_name.category() == Some(gix::refs::Category::RemoteBranch)
} Try / catch
match oplog.restore(snapshot_id) {
Err(err) if err.to_string().contains("not a remote-tracking branch") => { /* pick another snapshot */ }
other => other,
} Prevention
- Never hand-edit snapshot metadata
- Validate ref category when writing refs into project metadata
When it happens
Trigger: Restoring an oplog snapshot whose recorded targetRef is not `refs/remotes/<remote>/<branch>`, e.g. `refs/heads/main` or `refs/tags/v1` stored in the snapshot's metadata tree.
Common situations: Hand-edited snapshot trees; snapshots written by an incompatible GitButler version or external tooling; migration artifacts from older formats.
Related errors
- snapshot checkout ref is not a local branch
- targetCommitId in project_meta.toml is null
- Invalid conflict stage '{}'
- snapshot checkout commit is null
- commit id mismatch: failed to recreate a commit from its par
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/abe5ecc0e1b4ddf0.
Report an issue: GitHub.