jdx/mise · error

origin changed while preparing publication; reconcile again

Error message

origin changed while preparing publication; reconcile again

What it means

Analogous to the local-head check, mise verifies the remote/origin head has not moved since the plan was built. If `heads.remote != upstream` (someone else pushed to the shared history repository between planning and publication), mise aborts and requires a fresh reconcile so the push is based on the current upstream state.

Source

Thrown at src/system/history/sync/publish.rs:23

use super::graph::Heads;
use super::network::{PushOutcome, Remote};
use crate::system::history::shadow::HistoryRepo;

/// Reconciliation and complete live application must precede publication.
/// A merge that still changes this machine's saved tree needs another pull.
pub(crate) fn build(
    repo: &HistoryRepo,
    upstream: Option<&str>,
    expected_local: Option<&str>,
    accepted: &BTreeSet<String>,
) -> Result<Option<String>> {
    let heads = Heads::read(repo)?;
    if heads.local.as_deref() != expected_local {
        bail!("local saved history changed while planning; reconcile again");
    }
    if heads.remote.as_deref() != upstream {
        bail!("origin changed while preparing publication; reconcile again");
    }
    let Some(local) = &heads.local else {
        return Ok(None);
    };
    if heads.remote.as_ref() == Some(local) {
        return Ok(None);
    }
    let tree = repo.output_tree_of(local)?;
    if let Some(remote) = &heads.remote
        && heads.base.as_ref() != Some(remote)
    {
        let (mut merged, mut conflicts) = repo.merge_tree(local, remote)?;
        // Enrollment is a keyed inventory, not arbitrary JSON text. Git's
        // line merge can conflict on independent additions or combine policy
        // changes into invalid metadata. Validate its structured merge first.
        if let Some(base) = &heads.base {
            use crate::system::history::manifest::Manifest;
            if let (Some(base), Some(ours), Some(theirs)) = (

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Pull/fetch again to observe the new origin state and rebuild the plan, then publish.
  2. Resolve any new conflicts the updated origin introduces (see the sync-paused flow), then publish.
  3. Reduce the window between plan and publish, or coordinate pushes within the team.

Example fix

// before: teammate pushed while you prepared
mise bootstrap dotfiles publish   # origin changed -> abort
// after
mise bootstrap dotfiles pull      # reconcile against new origin
mise bootstrap dotfiles publish
Defensive patterns

Strategy: retry

Validate before calling

const heads = await readHeads();
if (heads.remote !== expectedUpstream) {
  console.warn("origin moved; fetch and reconcile before publishing");
}

Try / catch

try {
  await publish();
} catch (e) {
  if (String(e.message).includes("origin changed while preparing")) {
    await pull();          // fetch + merge with new origin
    await publish();       // retry against updated upstream
  } else throw e;
}

Prevention

When it happens

Trigger: In publish `build`, `Heads::read(repo).remote != upstream`. Triggered when a teammate pushed new history to the origin between the fetch/plan step and the publish step, or another local process fetched and advanced the recorded remote head.

Common situations: Active team pushing to the shared history repo while you publish; a long gap between pull and publish during which others pushed; a scheduled fetch job updating the remote ref.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/72aebf4185dbda43. Report an issue: GitHub.