jdx/mise · error
forced publication is not supported
Error message
forced publication is not supported
What it means
The push method publishes history refs to the origin setup repository. It deliberately never performs force-pushes: a forced publication would overwrite upstream history that other machines may have based their state on. If any refspec starts with '+', the library bails instead of passing it to git.
Solutions
- Fetch from origin and reconcile (merge/rebase) local history with the upstream branch, then push a fast-forward
- Remove the '+' prefix from the refspec — use plain "src:dst" refspecs
- If upstream was intentionally rewritten, follow the documented reconcile flow (fetch, realign, re-publish) rather than forcing
Example fix
// before net.push(&repo, &["+refs/history/*:refs/history/*"])?; // bails // after net.fetch_with_depth(&repo, "origin", None)?; // reconcile first net.push(&repo, &["refs/history/*:refs/history/*"])?;
Defensive patterns
Strategy: try-catch
Validate before calling
if refspecs.iter().any(|r| r.starts_with('+')) {
return Err(anyhow!("remove '+' from refspecs; force-push is not supported"));
} Try / catch
match net.push(&repo, &refspecs) {
Ok(PushOutcome::Pushed) => { /* done */ }
Ok(PushOutcome::Rejected(msg)) | Err(e) => {
// fetch and reconcile, then retry without forcing
net.fetch_with_depth(&repo, "origin", None)?;
reconcile_and_push()?;
}
} Prevention
- Never construct refspecs with a leading '+' in automation touching history refs
- On non-fast-forward rejection, always fetch + reconcile instead of reaching for force
- Teach recovery scripts to use the documented reconcile flow
When it happens
Trigger: Calling Network::push with a refspec string beginning with '+' (e.g. "+refs/heads/main:refs/heads/main") — typically constructed by caller code that hit a non-fast-forward and tried to force it through.
Common situations: Diverged local and origin history after another machine rewrote/pushed history; attempting to recover from a rejected push by force; copy-pasted refspecs from generic git workflows that assume --force is fine.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- cannot onboard this setup repository: history is unavailable
- configuration disappeared from preview commit
- could not snapshot the local history repository for preview
- incoming configuration must be a regular file
- incoming setup deletes required source
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/368b9013a4061fcf.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/sync/network.rs:250
pub(crate) fn push(
&self,
refspecs: &[String],
lease: Option<(&str, Option<&str>)>,
) -> Result<PushOutcome> {
validate_url(&self.url)?;
let mut args = vec!["push".to_string(), "--quiet".to_string()];
if let Some((branch, expected)) = lease {
let name = format!("refs/heads/{branch}");
let refs = self.ls_remote()?;
let observed = refs.iter().find(|(_, candidate)| candidate == &name);
if observed.map(|(oid, _)| oid.as_str()) != expected {
return Ok(PushOutcome::Rejected(
"the origin branch changed; fetch and reconcile before pushing".into(),
));
}
}
if refspecs.iter().any(|refspec| refspec.starts_with('+')) {
bail!("forced publication is not supported");
}
args.push("--".into());
args.push(self.url.clone());
args.extend(refspecs.iter().cloned());
let output = self.repo.network(args.iter().map(String::as_str))?;
if output.status.success() {
return Ok(PushOutcome::Done);
}
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
if stderr.contains("stale info")
|| stderr.contains("rejected")
|| stderr.contains("fetch first")
{
return Ok(PushOutcome::Rejected(stderr));
}
Err(NetworkError(format!("pushing to {}: {stderr}", self.url)).into())
}
View on GitHub (pinned to 533346cc37)