gitbutlerapp/gitbutler · error
push failed
Error message
push failed
What it means
After publishing session metadata, but-agentlog pushes the GitMeta ref in a retry loop (up to 5 attempts) that only retries non-fast-forward conflicts. This bail means `push_once` reported failure with `non_fast_forward == false` — the push was rejected for a reason other than a racing writer, so retrying the loop would not help. Typical causes are authentication, network, or remote-ref problems on the metadata remote.
Source
Thrown at crates/but-agentlog/src/gitmeta/write.rs:298
match gitmeta.pull(None) {
Ok(_) => {}
// An empty metadata remote has no ref yet; the push below initializes it.
Err(git_meta_lib::Error::GitCommand(message))
if message.contains("couldn't find remote ref") => {}
Err(err) => return Err(err).context("failed to pull GitMeta metadata"),
}
let mut attempts = 0;
loop {
attempts += 1;
let output = gitmeta
.push_once(None)
.context("failed to push GitMeta metadata")?;
if output.success {
return Ok(());
}
if !output.non_fast_forward {
bail!("push failed");
}
if attempts >= MAX_RETRIES {
bail!("push failed after {MAX_RETRIES} attempts");
}
gitmeta
.resolve_push_conflict(None)
.context("failed to resolve GitMeta push conflict")?;
}
}
fn stored_text(kind: RecordKind, text: Option<&str>) -> Option<String> {
let text = text?;
Some(match kind {
RecordKind::ToolResult => redact_text(cap_tool_result_text(text).as_ref()),
_ => redact_text(text),
})
}
View on GitHub (pinned to caf1f223d3)
Solutions
- Check network access and credentials for the GitMeta remote (`git ls-remote <metadata-remote-url>`) and fix auth
- Run `but agentlog sync` to confirm pull works, then retry publish — local state is intact, only the push failed
- Verify the GitMeta remote repository still exists and the account has push rights
- Re-run publish once auth is fixed; the record dedup (`:record-hashes`) prevents duplicates on the retry
Example fix
// before: single publish call surfaces the raw bail
publish_session(&repo, &session)?;
// after: retry publish after fixing auth, dedup makes it idempotent
let mut last_err = None;
for _ in 0..3 {
match publish_session(&repo, &session) {
Ok(()) => { last_err = None; break }
Err(e) if e.to_string().contains("push failed") => { last_err = Some(e); continue }
Err(e) => return Err(e),
}
}
if let Some(e) = last_err { return Err(e.context("metadata push rejected; check GitMeta remote auth")) } Defensive patterns
Strategy: retry
Validate before calling
// Verify the metadata remote is reachable and writable before publish
let ok = std::process::Command::new("git")
.args(["ls-remote", &metadata_remote_url])
.output()
.map(|o| o.status.success())
.unwrap_or(false);
if !ok { eprintln!("GitMeta remote unreachable or unauthorized"); } Type guard
fn push_output_is_retryable(output: &PushOutput) -> bool {
!output.success && output.non_fast_forward
} Try / catch
match publish(&repo, &session) {
Ok(()) => {}
Err(err) if err.to_string().contains("push failed") => {
// fix auth/network, then retry: record dedup makes this idempotent
retry_after_auth_fix()
}
Err(err) => return Err(err),
} Prevention
- Keep credentials for the GitMeta remote current (SSH agent / credential helper)
- Run a preflight `git ls-remote` on the metadata remote before batch publishes
- Treat a non-fast_forward push failure as permanent until auth/network is fixed — the retry loop will not help
When it happens
Trigger: The final step of `but agentlog publish` (or sync) calling `gitmeta.push_once` and getting an unsuccessful output that is not a non-fast-forward rejection — e.g. expired credentials for the GitMeta remote, unreachable remote, or permission loss on the remote ref.
Common situations: Expired SSH key or credential helper for the metadata remote URL; VPN/network drop mid-publish; the GitMeta remote repository was deleted or made read-only; remote hosting auth changes (token revoked, SSO enforced).
Related errors
- existing GitMeta key '{local_key}' is not a set
- push failed after {MAX_RETRIES} attempts
- existing GitMeta key '{associated_targets_key}' is not a str
- existing GitMeta key '{updated_at_key}' is not a string
- existing GitMeta key '{index_key}' is not a set
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/82353dda6ba5d678.
Report an issue: GitHub.