gitbutlerapp/gitbutler · error

Starting index state can only be fetched while in edit mode

Error message

Starting index state can only be fetched while in edit mode

What it means

`starting_index_state` reconstructs the index state recorded when edit mode was entered, which only exists while the project operates in `OperatingMode::Edit`. It bails immediately in open-workspace mode (or any other mode). It is part of the edit-mode read APIs used to list conflicts and index entries.

Source

Thrown at crates/gitbutler-edit-mode/src/lib.rs:438

}

#[derive(Serialize, Debug, Clone)]
#[cfg_attr(feature = "export-schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct ConflictEntryPresence {
    pub ours: bool,
    pub theirs: bool,
    pub ancestor: bool,
}
#[cfg(feature = "export-schema")]
but_schemars::register_sdk_type!(ConflictEntryPresence);

pub(crate) fn starting_index_state(
    ctx: &Context,
    perm: &RepoShared,
) -> Result<Vec<(TreeChange, Option<ConflictEntryPresence>)>> {
    let OperatingMode::Edit(metadata) = operating_mode(ctx, perm)? else {
        bail!("Starting index state can only be fetched while in edit mode")
    };

    let repo = &*ctx.repo.get()?;
    let commit = repo.find_commit(metadata.commit_oid)?;
    let commit_parent_tree = if commit.is_conflicted() {
        but_core::Commit::try_from(commit.clone())?
            .tree_id_or_kind(but_core::commit::TreeKind::Base)?
            .detach()
    } else {
        commit
            .parent_ids()
            .next()
            .context("edited commit had no parent")?
            .object()?
            .try_into_commit()?
            .tree_id()?
            .detach()
    };

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Enter edit mode first, then query the starting index state
  2. Guard the call with `in_edit_mode(ctx, perm)?` or call `ensure_edit_mode(ctx, perm)` which fails with a clear mode error
  3. Re-read the operating mode if a concurrent mode switch is possible

Example fix

// before
let state = starting_index_state(&ctx, &perm)?;

// after
ensure_edit_mode(&ctx, &perm)?; // Err("Expected to be in edit mode") when wrong
let state = starting_index_state(&ctx, &perm)?;
Defensive patterns

Strategy: validation

Validate before calling

if !in_edit_mode(&ctx, &perm)? {
    return Err(anyhow::anyhow!("starting index state requires edit mode"));
}

Type guard

fn can_query_edit_mode_state(mode: &OperatingMode) -> bool {
    matches!(mode, OperatingMode::Edit(_))
}

Try / catch

match starting_index_state(&ctx, &perm) {
    Err(err) if err.to_string().contains("while in edit mode") => { /* enter edit mode or skip */ }
    other => other,
}

Prevention

When it happens

Trigger: Calling the starting-index/conflict listing path when the project is in open workspace mode; or when an operating-mode switch happened between the caller's own check and this call.

Common situations: App code listing conflicts without first entering edit mode; races between mode switching and background refreshes; stale mode state after a failed edit-mode session.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/e0bae2a0976c001a. Report an issue: GitHub.