jdx/mise · error
forced publication is not supported
Error message
forced publication is not supported
What it means
push refuses refspecs that begin with '+' (force-push). Force publication would overwrite history on the origin branch, which this history-sync code forbids by design; when the remote branch moved, the caller is told to fetch and reconcile instead.
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 afd2eddd3a)
Solutions
- Remove the leading '+' from the refspec and push normally.
- When push is rejected because the origin branch changed, fetch and reconcile (rebase/merge) locally, then push again.
- If history truly must be rewritten on origin, do it outside this API with plain git push --force, acknowledging the history-sync store does not support it.
Example fix
// before let outcome = remote.push(&["+main:main"])?; // after let outcome = remote.push(&["main:main"])?; // fetch + reconcile if rejected
Defensive patterns
Strategy: validation
Validate before calling
let force = refspecs.iter().any(|r| r.starts_with('+'));
if force { eprintln!("drop the leading '+' — forced publication is not supported"); } Try / catch
match remote.push(&refspecs) {
Err(e) if e.to_string().contains("forced publication") => {
// rebuild refspecs without '+' and reconcile first
}
other => other?,
} Prevention
- Never prefix refspecs with '+' when writing to history-sync stores.
- On PushOutcome::Rejected, fetch and reconcile instead of forcing.
- Review automation templates for legacy force-push flags.
- Keep local history linear with the origin to avoid the temptation to force.
When it happens
Trigger: Calling push with any refspec string starting with '+', e.g. '+main:main' or '+refs/heads/*:refs/heads/*', on the history sync network transport.
Common situations: A developer habitually adds '+' to 'make sure' the push lands; a rebased/rewritten local history makes plain push fail and the user reaches for force-push; automation templates carry force refspecs.
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
- publication kept being rejected after {attempts} attempts: {
- remote task path is not a regular file or directory: {}
- cannot encode #{value.class} as JSON
- git command failed with {status}
- {} exists but is not a git checkout with an origin remote
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/368b9013a4061fcf.
Report an issue: GitHub.